summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormjkwiatkowski <mati.rewa@gmail.com>2026-02-16 15:18:21 +0100
committermjkwiatkowski <mati.rewa@gmail.com>2026-02-16 15:18:21 +0100
commit2f16cb0f48eca4453e3e894b3d45a3aa09e6dcc0 (patch)
tree672d98baa2ac071f2c30de06d613254d0d8cd105
parent86d35fcec83057e346e4982b5a6908f25342a392 (diff)
feat: opendc -> kafka -> postgresql works; added protobuf encodingHEADmaster
-rw-r--r--README29
-rw-r--r--README.md55
-rw-r--r--build.gradle.kts2
-rw-r--r--opendc-common/build.gradle.kts19
-rw-r--r--opendc-common/src/main/java/org/opendc/common/ProtobufMetrics.java638
-rw-r--r--opendc-common/src/main/kotlin/org/opendc/common/utils/ConfigParser.kt37
-rw-r--r--opendc-common/src/main/kotlin/org/opendc/common/utils/Kafka.kt41
-rw-r--r--opendc-common/src/main/kotlin/org/opendc/common/utils/PostgresqlDB.kt39
-rw-r--r--opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/KafkaComputeMonitor.kt50
-rw-r--r--opendc-demo/build.gradle.kts4
-rw-r--r--opendc-demo/src/main/kotlin/org/opendc/demo/DemoComputeMonitor.kt42
-rw-r--r--opendc-demo/src/main/kotlin/org/opendc/demo/RunRequest.kt2
-rw-r--r--opendc-experiments/opendc-experiments-base/build.gradle.kts2
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt18
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt4
-rw-r--r--opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt11
-rw-r--r--opendc-web/build.gradle.kts27
-rw-r--r--opendc-web/opendc-web-client/build.gradle.kts35
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt73
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/PortfolioResource.kt67
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ProjectResource.kt54
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ScenarioResource.kt76
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/SchedulerResource.kt36
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TopologyResource.kt79
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TraceResource.kt42
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/AuthController.kt40
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/OpenIdAuthController.kt147
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/ClientUtils.kt60
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenRequest.kt62
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenResponse.kt40
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OpenIdConfiguration.kt43
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/JobResource.kt51
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt60
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt184
-rw-r--r--opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/TransportClient.kt64
-rw-r--r--opendc-web/opendc-web-proto/build.gradle.kts39
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/JobState.kt53
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Machine.kt40
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/MemoryUnit.kt34
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/OperationalPhenomena.kt31
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProcessingUnit.kt34
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProtocolError.kt28
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Rack.kt34
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Room.kt33
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/RoomTile.kt34
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Targets.kt37
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Trace.kt36
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Workload.kt44
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Job.kt51
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Portfolio.kt43
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Scenario.kt42
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Topology.kt40
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Job.kt40
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Portfolio.kt72
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Project.kt46
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/ProjectRole.kt43
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Scenario.kt86
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Topology.kt75
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/User.kt31
-rw-r--r--opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/UserAccounting.kt34
-rw-r--r--opendc-web/opendc-web-runner-quarkus-deployment/build.gradle.kts37
-rw-r--r--opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerBuildItem.java42
-rw-r--r--opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerConfig.java38
-rw-r--r--opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerProcessor.java120
-rw-r--r--opendc-web/opendc-web-runner-quarkus/build.gradle.kts47
-rw-r--r--opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRecorder.java79
-rw-r--r--opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRuntimeConfig.java70
-rw-r--r--opendc-web/opendc-web-runner-quarkus/src/main/resources/META-INF/quarkus-extension.yaml5
-rw-r--r--opendc-web/opendc-web-runner/Dockerfile27
-rw-r--r--opendc-web/opendc-web-runner/build.gradle.kts91
-rw-r--r--opendc-web/opendc-web-runner/src/cli/kotlin/org/opendc/web/runner/Main.kt132
-rw-r--r--opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/JobManager.kt82
-rw-r--r--opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt385
-rw-r--r--opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/JobManagerImpl.kt69
-rw-r--r--opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/WebComputeMonitor.kt134
-rw-r--r--opendc-web/opendc-web-runner/src/main/resources/log4j2.xml48
-rw-r--r--opendc-web/opendc-web-server/Dockerfile33
-rw-r--r--opendc-web/opendc-web-server/build.gradle.kts96
-rw-r--r--opendc-web/opendc-web-server/config/application.properties1
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java166
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java151
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java237
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java172
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java197
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java153
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java72
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java167
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java61
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java50
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java52
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java70
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java46
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java51
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java110
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java78
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java161
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java159
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java131
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java127
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java208
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java132
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java73
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java81
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java136
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java64
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java39
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java39
-rw-r--r--opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java114
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.pngbin2825 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-dev.properties36
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-docker.properties49
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-prod.properties36
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application-test.properties43
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/application.properties49
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties1
-rw-r--r--opendc-web/opendc-web-server/src/main/resources/load_data.sql124
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/SchedulerResourceTest.java44
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/TraceResourceTest.java66
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/runner/JobResourceTest.java144
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioResourceTest.java284
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioScenarioResourceTest.java273
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ProjectResourceTest.java196
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ScenarioResourceTest.java178
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/TopologyResourceTest.java358
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/UserResourceTest.java65
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/JobServiceTest.java124
-rw-r--r--opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/UserAccountingServiceTest.java213
-rw-r--r--opendc-web/opendc-web-ui-quarkus-deployment/build.gradle.kts39
-rw-r--r--opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java51
-rw-r--r--opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java56
-rw-r--r--opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java301
-rw-r--r--opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java118
-rw-r--r--opendc-web/opendc-web-ui-quarkus/build.gradle.kts42
-rw-r--r--opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java98
-rw-r--r--opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java39
-rw-r--r--opendc-web/opendc-web-ui-quarkus/src/main/resources/META-INF/quarkus-extension.yaml5
-rw-r--r--opendc-web/opendc-web-ui/.dockerignore9
-rw-r--r--opendc-web/opendc-web-ui/.eslintrc16
-rw-r--r--opendc-web/opendc-web-ui/.gitignore27
-rw-r--r--opendc-web/opendc-web-ui/.prettierrc.yaml5
-rw-r--r--opendc-web/opendc-web-ui/Dockerfile36
-rw-r--r--opendc-web/opendc-web-ui/README.md106
-rw-r--r--opendc-web/opendc-web-ui/build.gradle.kts144
-rw-r--r--opendc-web/opendc-web-ui/next.config.js43
-rw-r--r--opendc-web/opendc-web-ui/package-lock.json4665
-rw-r--r--opendc-web/opendc-web-ui/package.json76
-rw-r--r--opendc-web/opendc-web-ui/public/favicon.icobin99678 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/humans.txt35
-rw-r--r--opendc-web/opendc-web-ui/public/img/avatar.svg18
-rw-r--r--opendc-web/opendc-web-ui/public/img/datacenter-drawing.pngbin207909 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/logo.pngbin2825 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/logo.svg191
-rw-r--r--opendc-web/opendc-web-ui/public/img/opendc-architecture.pngbin45056 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/opendc-timeline-v2.pngbin33460 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/aiosup.pngbin71879 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/evaneyk.pngbin89028 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/fmastenbroek.pngbin123006 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/gandreadis.pngbin76426 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/hhe.pngbin102718 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/jbosch.pngbin101618 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/jburley.pngbin328112 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/lfdversluis.pngbin67796 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/loverweel.pngbin65866 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/sjounaid.pngbin94523 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/vvanbeek.pngbin85159 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/portraits/wlai.pngbin72873 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/screenshot-construction.pngbin275103 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/screenshot-simulation.pngbin291836 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/stakeholders/Developer.pngbin11411 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/stakeholders/Manager.pngbin9946 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/stakeholders/Researcher.pngbin10984 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/stakeholders/Sales.pngbin10074 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/stakeholders/Student.pngbin12960 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/topology/cpu-icon.pngbin4062 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/topology/gpu-icon.pngbin2227 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/topology/memory-icon.pngbin1980 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/topology/rack-energy-icon.pngbin893 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/topology/rack-space-icon.pngbin957 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/topology/storage-icon.pngbin4038 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/img/tudelft-icon.pngbin4387 -> 0 bytes
-rw-r--r--opendc-web/opendc-web-ui/public/manifest.json15
-rw-r--r--opendc-web/opendc-web-ui/public/robots.txt3
-rwxr-xr-xopendc-web/opendc-web-ui/scripts/envsubst.sh14
-rw-r--r--opendc-web/opendc-web-ui/src/api/index.js56
-rw-r--r--opendc-web/opendc-web-ui/src/api/portfolios.js39
-rw-r--r--opendc-web/opendc-web-ui/src/api/projects.js39
-rw-r--r--opendc-web/opendc-web-ui/src/api/scenarios.js39
-rw-r--r--opendc-web/opendc-web-ui/src/api/schedulers.js27
-rw-r--r--opendc-web/opendc-web-ui/src/api/topologies.js44
-rw-r--r--opendc-web/opendc-web-ui/src/api/traces.js27
-rw-r--r--opendc-web/opendc-web-ui/src/api/users.js32
-rw-r--r--opendc-web/opendc-web-ui/src/auth.js97
-rw-r--r--opendc-web/opendc-web-ui/src/components/AppHeader.js69
-rw-r--r--opendc-web/opendc-web-ui/src/components/AppHeader.module.css42
-rw-r--r--opendc-web/opendc-web-ui/src/components/AppHeaderTools.js93
-rw-r--r--opendc-web/opendc-web-ui/src/components/AppHeaderUser.js99
-rw-r--r--opendc-web/opendc-web-ui/src/components/AppPage.js44
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js34
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.css28
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelector.js79
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.css44
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js52
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js55
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/TopologySelector.js52
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js60
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js157
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js120
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResultInfo.js40
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js180
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js62
-rw-r--r--opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js103
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js26
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.css7
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/NewPortfolio.js53
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/NewPortfolioModal.js161
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/NewTopology.js57
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/NewTopologyModal.js115
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js99
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/ProjectCollection.js137
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/ProjectOverview.js98
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js115
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js74
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js69
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/TopologyOverview.js92
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/GrayContainer.js34
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/MapConstants.js25
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js83
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.module.css29
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/RackContainer.js37
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/RackEnergyFillContainer.js36
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/RackSpaceFillContainer.js42
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/RoomContainer.js54
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/TileContainer.js50
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/TopologyContainer.js34
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/WallContainer.js39
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.js42
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.module.css55
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.js18
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.module.css10
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.js33
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.module.css27
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/Backdrop.js10
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/GrayLayer.js24
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/HoverTile.js30
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/ImageComponent.js37
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/RackFillBar.js68
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/RoomTile.js24
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/TileObject.js27
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/TilePlusIcon.js44
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/elements/WallSegment.js32
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/groups/GridGroup.js36
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/groups/RackGroup.js25
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/groups/RoomGroup.js52
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/groups/TileGroup.js36
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/groups/TopologyGroup.js44
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/groups/WallGroup.js22
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js55
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js41
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js51
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js59
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/NameComponent.js69
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.js83
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.module.css35
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/BuildingSidebar.js8
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionComponent.js46
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionContainer.js46
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/DeleteMachine.js59
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/MachineSidebar.js55
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddComponent.js42
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js44
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js113
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js47
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitTabsComponent.js36
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js25
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/AddPrefab.js41
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/DeleteRackContainer.js60
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineComponent.js40
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListComponent.js80
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListContainer.js56
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackNameContainer.js22
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.js58
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.module.css14
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/DeleteRoomContainer.js59
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/EditRoomContainer.js61
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionComponent.js35
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionContainer.js46
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomName.js44
-rw-r--r--opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomSidebar.js43
-rw-r--r--opendc-web/opendc-web-ui/src/components/util/TableEmptyState.js103
-rw-r--r--opendc-web/opendc-web-ui/src/components/util/modals/ConfirmationModal.js27
-rw-r--r--opendc-web/opendc-web-ui/src/components/util/modals/Modal.js38
-rw-r--r--opendc-web/opendc-web-ui/src/components/util/modals/TextInputModal.js70
-rw-r--r--opendc-web/opendc-web-ui/src/config.js41
-rw-r--r--opendc-web/opendc-web-ui/src/data/experiments.js47
-rw-r--r--opendc-web/opendc-web-ui/src/data/project.js166
-rw-r--r--opendc-web/opendc-web-ui/src/data/query.js59
-rw-r--r--opendc-web/opendc-web-ui/src/data/topology.js88
-rw-r--r--opendc-web/opendc-web-ui/src/data/user.js40
-rw-r--r--opendc-web/opendc-web-ui/src/pages/404.js38
-rw-r--r--opendc-web/opendc-web-ui/src/pages/_app.js108
-rw-r--r--opendc-web/opendc-web-ui/src/pages/_document.js76
-rw-r--r--opendc-web/opendc-web-ui/src/pages/logout.js39
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js75
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js121
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js142
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/index.js116
-rw-r--r--opendc-web/opendc-web-ui/src/redux/actions/interaction-level.js57
-rw-r--r--opendc-web/opendc-web-ui/src/redux/actions/topology/building.js113
-rw-r--r--opendc-web/opendc-web-ui/src/redux/actions/topology/index.js40
-rw-r--r--opendc-web/opendc-web-ui/src/redux/actions/topology/machine.js28
-rw-r--r--opendc-web/opendc-web-ui/src/redux/actions/topology/rack.js36
-rw-r--r--opendc-web/opendc-web-ui/src/redux/actions/topology/room.js74
-rw-r--r--opendc-web/opendc-web-ui/src/redux/index.js59
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/construction-mode.js43
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/index.js12
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/interaction-level.js68
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/topology/index.js44
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/topology/machine.js47
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/topology/rack.js66
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/topology/room.js65
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/topology/tile.js58
-rw-r--r--opendc-web/opendc-web-ui/src/redux/reducers/topology/topology.js47
-rw-r--r--opendc-web/opendc-web-ui/src/redux/sagas/index.js7
-rw-r--r--opendc-web/opendc-web-ui/src/redux/sagas/topology.js76
-rw-r--r--opendc-web/opendc-web-ui/src/shapes.js187
-rw-r--r--opendc-web/opendc-web-ui/src/style/index.css28
-rw-r--r--opendc-web/opendc-web-ui/src/util/authorizations.js21
-rw-r--r--opendc-web/opendc-web-ui/src/util/available-metrics.js101
-rw-r--r--opendc-web/opendc-web-ui/src/util/colors.js29
-rw-r--r--opendc-web/opendc-web-ui/src/util/date-time.js81
-rw-r--r--opendc-web/opendc-web-ui/src/util/date-time.test.js21
-rw-r--r--opendc-web/opendc-web-ui/src/util/effect-ref.js41
-rw-r--r--opendc-web/opendc-web-ui/src/util/tile-calculations.js255
-rw-r--r--opendc-web/opendc-web-ui/src/util/topology-schema.js47
-rw-r--r--opendc-web/opendc-web-ui/src/util/unit-specifications.js102
-rw-r--r--resources/experiments/config.json4
-rw-r--r--resources/experiments/schema.proto11
-rw-r--r--resources/experiments/sink-jdbc.properties46
338 files changed, 936 insertions, 24601 deletions
diff --git a/README b/README
deleted file mode 100644
index d3aedcc4..00000000
--- a/README
+++ /dev/null
@@ -1,29 +0,0 @@
-#Dependencies
-
-Kafka:
-
-extra/kafka 4.1.1-1
-
-```bash
-sudo -u kafka /usr/bin/kafka-storage.sh format -t "$(/usr/bin/kafka-storage.sh random-uuid)" -c /etc/kafka/server.properties --standalone
-systemctl enable kafka
-systemctl start kafka
-```
-
-```bash
-bin/kafka-topics.sh --create --topic postgres-topic --bootstrap-server localhost:9092 --partitions 1 --replication-factor 1
-bin/kafka-topics.sh --list --bootstrap-server localhost:9092
-```
-
-
-Postgresql:
-
-extra/postgresql 18.1-2
-
-```bash
-initdb -D /var/lib/postgres/data
-mkdir /run/postgresql/
-cd /run/postgresql/
-touch .s.PGSQL.5432.lock
-chown -R postgres:postgres /run/postgresql
-```
diff --git a/README.md b/README.md
new file mode 100644
index 00000000..5267b498
--- /dev/null
+++ b/README.md
@@ -0,0 +1,55 @@
+### Dependencies
+
+Paths are hardcoded.
+
+Confluent local (see https://www.confluent.io/installation/):
+
+```bash
+export CONFLUENT_HOME=/opt/confluent
+export PATH=/opt/confluent/bin:$PATH
+cd /opt/confluent
+kafka-storage.sh random-uuid
+kafka-storage.sh format -t 2vi2WtHxQAOPyXb1Bj1Jvw -c etc/kafka/server.properties
+kafka-server-start.sh etc/kafka/server.properties
+kafka-server-start etc/kafka/server.properties
+schema-registry-start $CONFLUENT_HOME/etc/schema-registry/schema-registry.properties
+connect-standalone $CONFLUENT_HOME/etc/kafka/connect-standalone.properties $CONFLUENT_HOME/share/confluent-common/connectors/sink-jdbc.properties
+```
+
+Confluent JDBC sink and source (includes Postgres connector)
+(see https://www.confluent.io/hub/confluentinc/kafka-connect-jdbc)
+Be mindful to configure the right `plugin.path` in `etc/kafka/connect-standalone.properties`
+```bash
+ln -s $HOME/git/opendc/resources/experiments/sink-jdbc.properties opt/confluent/share/confluent-common/connectors/sink-jdbc.properties
+```
+
+Protobuf:
+
+extra/protobuf 33.1-3
+
+You need to run this each time you change `schema.proto`
+```bash
+cd resources/experiments/
+protoc --java_out=/home/matt/git/opendc/opendc-common/src/main/java/ schema.proto
+```
+
+Postgresql:
+
+extra/postgresql 18.1-2
+
+```bash
+initdb -D /var/lib/postgres/data
+mkdir /run/postgresql/
+cd /run/postgresql/
+touch .s.PGSQL.5432.lock
+chown -R postgres:postgres /run/postgresql
+```
+
+
+Random
+```bash
+bin/kafka-topics.sh --bootstrap-server localhost:9092 --delete --topic postgres-topic
+bin/kafka-topics.sh --create --topic postgres-topic --bootstrap-server localhost:9092 --partitions 1 --replication-factor 1
+bin/kafka-topics.sh --list --bootstrap-server localhost:9092
+bin/kafka-console-consumer.sh --bootstrap-server :9092 --topic postgres-topic --from-beginning
+``` \ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 29d9202b..f8a20895 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -25,4 +25,4 @@ plugins {
}
group = "org.opendc"
-version = "3.0-SNAPSHOT" \ No newline at end of file
+version = "3.0-SNAPSHOT"
diff --git a/opendc-common/build.gradle.kts b/opendc-common/build.gradle.kts
index 0094730b..4d9e8b54 100644
--- a/opendc-common/build.gradle.kts
+++ b/opendc-common/build.gradle.kts
@@ -1,3 +1,4 @@
+
/*
* Copyright (c) 2020 AtLarge Research
*
@@ -29,6 +30,11 @@ plugins {
kotlin("plugin.serialization") version "1.9.22"
}
+repositories {
+ maven(url = "https://packages.confluent.io/maven/")
+}
+
+
val serializationVersion = "1.6.0"
dependencies {
@@ -45,4 +51,17 @@ dependencies {
api(libs.kotlin.logging)
testImplementation(projects.opendcSimulator.opendcSimulatorCore)
+
+ // Source: https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients
+ implementation("org.apache.kafka:kafka-clients:4.1.1")
+ implementation(libs.jackson.core)
+
+ // Source: https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java
+ // @Mateusz crucial this is an _api_ and not _implementation_
+ api("com.google.protobuf:protobuf-java:4.33.5")
+
+ // Source: https://mvnrepository.com/artifact/io.confluent/kafka-protobuf-serializer
+ implementation("io.confluent:kafka-protobuf-serializer:8.1.1")
}
+
+
diff --git a/opendc-common/src/main/java/org/opendc/common/ProtobufMetrics.java b/opendc-common/src/main/java/org/opendc/common/ProtobufMetrics.java
new file mode 100644
index 00000000..0ec97cd0
--- /dev/null
+++ b/opendc-common/src/main/java/org/opendc/common/ProtobufMetrics.java
@@ -0,0 +1,638 @@
+// Generated by the protocol buffer compiler. DO NOT EDIT!
+// NO CHECKED-IN PROTOBUF GENCODE
+// source: schema.proto
+// Protobuf Java Version: 4.33.1
+
+package org.opendc.common;
+
+@com.google.protobuf.Generated
+public final class ProtobufMetrics extends com.google.protobuf.GeneratedFile {
+ private ProtobufMetrics() {}
+ static {
+ com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(
+ com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,
+ /* major= */ 4,
+ /* minor= */ 33,
+ /* patch= */ 1,
+ /* suffix= */ "",
+ "ProtobufMetrics");
+ }
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistryLite registry) {
+ }
+
+ public static void registerAllExtensions(
+ com.google.protobuf.ExtensionRegistry registry) {
+ registerAllExtensions(
+ (com.google.protobuf.ExtensionRegistryLite) registry);
+ }
+ public interface ProtoExportOrBuilder extends
+ // @@protoc_insertion_point(interface_extends:proto.ProtoExport)
+ com.google.protobuf.MessageOrBuilder {
+
+ /**
+ * <code>required int32 id = 1;</code>
+ * @return Whether the id field is set.
+ */
+ boolean hasId();
+ /**
+ * <code>required int32 id = 1;</code>
+ * @return The id.
+ */
+ int getId();
+
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @return Whether the tasksactive field is set.
+ */
+ boolean hasTasksactive();
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @return The tasksactive.
+ */
+ int getTasksactive();
+ }
+ /**
+ * Protobuf type {@code proto.ProtoExport}
+ */
+ public static final class ProtoExport extends
+ com.google.protobuf.GeneratedMessage implements
+ // @@protoc_insertion_point(message_implements:proto.ProtoExport)
+ ProtoExportOrBuilder {
+ private static final long serialVersionUID = 0L;
+ static {
+ com.google.protobuf.RuntimeVersion.validateProtobufGencodeVersion(
+ com.google.protobuf.RuntimeVersion.RuntimeDomain.PUBLIC,
+ /* major= */ 4,
+ /* minor= */ 33,
+ /* patch= */ 1,
+ /* suffix= */ "",
+ "ProtoExport");
+ }
+ // Use ProtoExport.newBuilder() to construct.
+ private ProtoExport(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+ super(builder);
+ }
+ private ProtoExport() {
+ }
+
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.opendc.common.ProtobufMetrics.internal_static_proto_ProtoExport_descriptor;
+ }
+
+ @java.lang.Override
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.opendc.common.ProtobufMetrics.internal_static_proto_ProtoExport_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.opendc.common.ProtobufMetrics.ProtoExport.class, org.opendc.common.ProtobufMetrics.ProtoExport.Builder.class);
+ }
+
+ private int bitField0_;
+ public static final int ID_FIELD_NUMBER = 1;
+ private int id_ = 0;
+ /**
+ * <code>required int32 id = 1;</code>
+ * @return Whether the id field is set.
+ */
+ @java.lang.Override
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000001) != 0);
+ }
+ /**
+ * <code>required int32 id = 1;</code>
+ * @return The id.
+ */
+ @java.lang.Override
+ public int getId() {
+ return id_;
+ }
+
+ public static final int TASKSACTIVE_FIELD_NUMBER = 2;
+ private int tasksactive_ = 0;
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @return Whether the tasksactive field is set.
+ */
+ @java.lang.Override
+ public boolean hasTasksactive() {
+ return ((bitField0_ & 0x00000002) != 0);
+ }
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @return The tasksactive.
+ */
+ @java.lang.Override
+ public int getTasksactive() {
+ return tasksactive_;
+ }
+
+ private byte memoizedIsInitialized = -1;
+ @java.lang.Override
+ public final boolean isInitialized() {
+ byte isInitialized = memoizedIsInitialized;
+ if (isInitialized == 1) return true;
+ if (isInitialized == 0) return false;
+
+ if (!hasId()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
+ if (!hasTasksactive()) {
+ memoizedIsInitialized = 0;
+ return false;
+ }
+ memoizedIsInitialized = 1;
+ return true;
+ }
+
+ @java.lang.Override
+ public void writeTo(com.google.protobuf.CodedOutputStream output)
+ throws java.io.IOException {
+ if (((bitField0_ & 0x00000001) != 0)) {
+ output.writeInt32(1, id_);
+ }
+ if (((bitField0_ & 0x00000002) != 0)) {
+ output.writeInt32(2, tasksactive_);
+ }
+ getUnknownFields().writeTo(output);
+ }
+
+ @java.lang.Override
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) return size;
+
+ size = 0;
+ if (((bitField0_ & 0x00000001) != 0)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(1, id_);
+ }
+ if (((bitField0_ & 0x00000002) != 0)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeInt32Size(2, tasksactive_);
+ }
+ size += getUnknownFields().getSerializedSize();
+ memoizedSize = size;
+ return size;
+ }
+
+ @java.lang.Override
+ public boolean equals(final java.lang.Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof org.opendc.common.ProtobufMetrics.ProtoExport)) {
+ return super.equals(obj);
+ }
+ org.opendc.common.ProtobufMetrics.ProtoExport other = (org.opendc.common.ProtobufMetrics.ProtoExport) obj;
+
+ if (hasId() != other.hasId()) return false;
+ if (hasId()) {
+ if (getId()
+ != other.getId()) return false;
+ }
+ if (hasTasksactive() != other.hasTasksactive()) return false;
+ if (hasTasksactive()) {
+ if (getTasksactive()
+ != other.getTasksactive()) return false;
+ }
+ if (!getUnknownFields().equals(other.getUnknownFields())) return false;
+ return true;
+ }
+
+ @java.lang.Override
+ public int hashCode() {
+ if (memoizedHashCode != 0) {
+ return memoizedHashCode;
+ }
+ int hash = 41;
+ hash = (19 * hash) + getDescriptor().hashCode();
+ if (hasId()) {
+ hash = (37 * hash) + ID_FIELD_NUMBER;
+ hash = (53 * hash) + getId();
+ }
+ if (hasTasksactive()) {
+ hash = (37 * hash) + TASKSACTIVE_FIELD_NUMBER;
+ hash = (53 * hash) + getTasksactive();
+ }
+ hash = (29 * hash) + getUnknownFields().hashCode();
+ memoizedHashCode = hash;
+ return hash;
+ }
+
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ java.nio.ByteBuffer data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ java.nio.ByteBuffer data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ com.google.protobuf.ByteString data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ com.google.protobuf.ByteString data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(byte[] data)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ byte[] data,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ return PARSER.parseFrom(data, extensionRegistry);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessage
+ .parseWithIOException(PARSER, input);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessage
+ .parseWithIOException(PARSER, input, extensionRegistry);
+ }
+
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseDelimitedFrom(java.io.InputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessage
+ .parseDelimitedWithIOException(PARSER, input);
+ }
+
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseDelimitedFrom(
+ java.io.InputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessage
+ .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ com.google.protobuf.CodedInputStream input)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessage
+ .parseWithIOException(PARSER, input);
+ }
+ public static org.opendc.common.ProtobufMetrics.ProtoExport parseFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ return com.google.protobuf.GeneratedMessage
+ .parseWithIOException(PARSER, input, extensionRegistry);
+ }
+
+ @java.lang.Override
+ public Builder newBuilderForType() { return newBuilder(); }
+ public static Builder newBuilder() {
+ return DEFAULT_INSTANCE.toBuilder();
+ }
+ public static Builder newBuilder(org.opendc.common.ProtobufMetrics.ProtoExport prototype) {
+ return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+ }
+ @java.lang.Override
+ public Builder toBuilder() {
+ return this == DEFAULT_INSTANCE
+ ? new Builder() : new Builder().mergeFrom(this);
+ }
+
+ @java.lang.Override
+ protected Builder newBuilderForType(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ Builder builder = new Builder(parent);
+ return builder;
+ }
+ /**
+ * Protobuf type {@code proto.ProtoExport}
+ */
+ public static final class Builder extends
+ com.google.protobuf.GeneratedMessage.Builder<Builder> implements
+ // @@protoc_insertion_point(builder_implements:proto.ProtoExport)
+ org.opendc.common.ProtobufMetrics.ProtoExportOrBuilder {
+ public static final com.google.protobuf.Descriptors.Descriptor
+ getDescriptor() {
+ return org.opendc.common.ProtobufMetrics.internal_static_proto_ProtoExport_descriptor;
+ }
+
+ @java.lang.Override
+ protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internalGetFieldAccessorTable() {
+ return org.opendc.common.ProtobufMetrics.internal_static_proto_ProtoExport_fieldAccessorTable
+ .ensureFieldAccessorsInitialized(
+ org.opendc.common.ProtobufMetrics.ProtoExport.class, org.opendc.common.ProtobufMetrics.ProtoExport.Builder.class);
+ }
+
+ // Construct using org.opendc.common.ProtobufMetrics.ProtoExport.newBuilder()
+ private Builder() {
+
+ }
+
+ private Builder(
+ com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+ super(parent);
+
+ }
+ @java.lang.Override
+ public Builder clear() {
+ super.clear();
+ bitField0_ = 0;
+ id_ = 0;
+ tasksactive_ = 0;
+ return this;
+ }
+
+ @java.lang.Override
+ public com.google.protobuf.Descriptors.Descriptor
+ getDescriptorForType() {
+ return org.opendc.common.ProtobufMetrics.internal_static_proto_ProtoExport_descriptor;
+ }
+
+ @java.lang.Override
+ public org.opendc.common.ProtobufMetrics.ProtoExport getDefaultInstanceForType() {
+ return org.opendc.common.ProtobufMetrics.ProtoExport.getDefaultInstance();
+ }
+
+ @java.lang.Override
+ public org.opendc.common.ProtobufMetrics.ProtoExport build() {
+ org.opendc.common.ProtobufMetrics.ProtoExport result = buildPartial();
+ if (!result.isInitialized()) {
+ throw newUninitializedMessageException(result);
+ }
+ return result;
+ }
+
+ @java.lang.Override
+ public org.opendc.common.ProtobufMetrics.ProtoExport buildPartial() {
+ org.opendc.common.ProtobufMetrics.ProtoExport result = new org.opendc.common.ProtobufMetrics.ProtoExport(this);
+ if (bitField0_ != 0) { buildPartial0(result); }
+ onBuilt();
+ return result;
+ }
+
+ private void buildPartial0(org.opendc.common.ProtobufMetrics.ProtoExport result) {
+ int from_bitField0_ = bitField0_;
+ int to_bitField0_ = 0;
+ if (((from_bitField0_ & 0x00000001) != 0)) {
+ result.id_ = id_;
+ to_bitField0_ |= 0x00000001;
+ }
+ if (((from_bitField0_ & 0x00000002) != 0)) {
+ result.tasksactive_ = tasksactive_;
+ to_bitField0_ |= 0x00000002;
+ }
+ result.bitField0_ |= to_bitField0_;
+ }
+
+ @java.lang.Override
+ public Builder mergeFrom(com.google.protobuf.Message other) {
+ if (other instanceof org.opendc.common.ProtobufMetrics.ProtoExport) {
+ return mergeFrom((org.opendc.common.ProtobufMetrics.ProtoExport)other);
+ } else {
+ super.mergeFrom(other);
+ return this;
+ }
+ }
+
+ public Builder mergeFrom(org.opendc.common.ProtobufMetrics.ProtoExport other) {
+ if (other == org.opendc.common.ProtobufMetrics.ProtoExport.getDefaultInstance()) return this;
+ if (other.hasId()) {
+ setId(other.getId());
+ }
+ if (other.hasTasksactive()) {
+ setTasksactive(other.getTasksactive());
+ }
+ this.mergeUnknownFields(other.getUnknownFields());
+ onChanged();
+ return this;
+ }
+
+ @java.lang.Override
+ public final boolean isInitialized() {
+ if (!hasId()) {
+ return false;
+ }
+ if (!hasTasksactive()) {
+ return false;
+ }
+ return true;
+ }
+
+ @java.lang.Override
+ public Builder mergeFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws java.io.IOException {
+ if (extensionRegistry == null) {
+ throw new java.lang.NullPointerException();
+ }
+ try {
+ boolean done = false;
+ while (!done) {
+ int tag = input.readTag();
+ switch (tag) {
+ case 0:
+ done = true;
+ break;
+ case 8: {
+ id_ = input.readInt32();
+ bitField0_ |= 0x00000001;
+ break;
+ } // case 8
+ case 16: {
+ tasksactive_ = input.readInt32();
+ bitField0_ |= 0x00000002;
+ break;
+ } // case 16
+ default: {
+ if (!super.parseUnknownField(input, extensionRegistry, tag)) {
+ done = true; // was an endgroup tag
+ }
+ break;
+ } // default:
+ } // switch (tag)
+ } // while (!done)
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.unwrapIOException();
+ } finally {
+ onChanged();
+ } // finally
+ return this;
+ }
+ private int bitField0_;
+
+ private int id_ ;
+ /**
+ * <code>required int32 id = 1;</code>
+ * @return Whether the id field is set.
+ */
+ @java.lang.Override
+ public boolean hasId() {
+ return ((bitField0_ & 0x00000001) != 0);
+ }
+ /**
+ * <code>required int32 id = 1;</code>
+ * @return The id.
+ */
+ @java.lang.Override
+ public int getId() {
+ return id_;
+ }
+ /**
+ * <code>required int32 id = 1;</code>
+ * @param value The id to set.
+ * @return This builder for chaining.
+ */
+ public Builder setId(int value) {
+
+ id_ = value;
+ bitField0_ |= 0x00000001;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>required int32 id = 1;</code>
+ * @return This builder for chaining.
+ */
+ public Builder clearId() {
+ bitField0_ = (bitField0_ & ~0x00000001);
+ id_ = 0;
+ onChanged();
+ return this;
+ }
+
+ private int tasksactive_ ;
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @return Whether the tasksactive field is set.
+ */
+ @java.lang.Override
+ public boolean hasTasksactive() {
+ return ((bitField0_ & 0x00000002) != 0);
+ }
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @return The tasksactive.
+ */
+ @java.lang.Override
+ public int getTasksactive() {
+ return tasksactive_;
+ }
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @param value The tasksactive to set.
+ * @return This builder for chaining.
+ */
+ public Builder setTasksactive(int value) {
+
+ tasksactive_ = value;
+ bitField0_ |= 0x00000002;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>required int32 tasksactive = 2;</code>
+ * @return This builder for chaining.
+ */
+ public Builder clearTasksactive() {
+ bitField0_ = (bitField0_ & ~0x00000002);
+ tasksactive_ = 0;
+ onChanged();
+ return this;
+ }
+
+ // @@protoc_insertion_point(builder_scope:proto.ProtoExport)
+ }
+
+ // @@protoc_insertion_point(class_scope:proto.ProtoExport)
+ private static final org.opendc.common.ProtobufMetrics.ProtoExport DEFAULT_INSTANCE;
+ static {
+ DEFAULT_INSTANCE = new org.opendc.common.ProtobufMetrics.ProtoExport();
+ }
+
+ public static org.opendc.common.ProtobufMetrics.ProtoExport getDefaultInstance() {
+ return DEFAULT_INSTANCE;
+ }
+
+ private static final com.google.protobuf.Parser<ProtoExport>
+ PARSER = new com.google.protobuf.AbstractParser<ProtoExport>() {
+ @java.lang.Override
+ public ProtoExport parsePartialFrom(
+ com.google.protobuf.CodedInputStream input,
+ com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+ throws com.google.protobuf.InvalidProtocolBufferException {
+ Builder builder = newBuilder();
+ try {
+ builder.mergeFrom(input, extensionRegistry);
+ } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+ throw e.setUnfinishedMessage(builder.buildPartial());
+ } catch (com.google.protobuf.UninitializedMessageException e) {
+ throw e.asInvalidProtocolBufferException().setUnfinishedMessage(builder.buildPartial());
+ } catch (java.io.IOException e) {
+ throw new com.google.protobuf.InvalidProtocolBufferException(e)
+ .setUnfinishedMessage(builder.buildPartial());
+ }
+ return builder.buildPartial();
+ }
+ };
+
+ public static com.google.protobuf.Parser<ProtoExport> parser() {
+ return PARSER;
+ }
+
+ @java.lang.Override
+ public com.google.protobuf.Parser<ProtoExport> getParserForType() {
+ return PARSER;
+ }
+
+ @java.lang.Override
+ public org.opendc.common.ProtobufMetrics.ProtoExport getDefaultInstanceForType() {
+ return DEFAULT_INSTANCE;
+ }
+
+ }
+
+ private static final com.google.protobuf.Descriptors.Descriptor
+ internal_static_proto_ProtoExport_descriptor;
+ private static final
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable
+ internal_static_proto_ProtoExport_fieldAccessorTable;
+
+ public static com.google.protobuf.Descriptors.FileDescriptor
+ getDescriptor() {
+ return descriptor;
+ }
+ private static com.google.protobuf.Descriptors.FileDescriptor
+ descriptor;
+ static {
+ java.lang.String[] descriptorData = {
+ "\n\014schema.proto\022\005proto\".\n\013ProtoExport\022\n\n\002" +
+ "id\030\001 \002(\005\022\023\n\013tasksactive\030\002 \002(\005B$\n\021org.ope" +
+ "ndc.commonB\017ProtobufMetrics"
+ };
+ descriptor = com.google.protobuf.Descriptors.FileDescriptor
+ .internalBuildGeneratedFileFrom(descriptorData,
+ new com.google.protobuf.Descriptors.FileDescriptor[] {
+ });
+ internal_static_proto_ProtoExport_descriptor =
+ getDescriptor().getMessageType(0);
+ internal_static_proto_ProtoExport_fieldAccessorTable = new
+ com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+ internal_static_proto_ProtoExport_descriptor,
+ new java.lang.String[] { "Id", "Tasksactive", });
+ descriptor.resolveAllFeaturesImmutable();
+ }
+
+ // @@protoc_insertion_point(outer_class_scope)
+}
diff --git a/opendc-common/src/main/kotlin/org/opendc/common/utils/ConfigParser.kt b/opendc-common/src/main/kotlin/org/opendc/common/utils/ConfigParser.kt
index cb9623bb..e6f18da5 100644
--- a/opendc-common/src/main/kotlin/org/opendc/common/utils/ConfigParser.kt
+++ b/opendc-common/src/main/kotlin/org/opendc/common/utils/ConfigParser.kt
@@ -11,32 +11,40 @@ import java.io.InputStream
import java.io.OutputStream
import java.net.Socket
import java.sql.Connection
-import java.sql.DriverManager
-import java.sql.SQLException
/**
+ * @author Mateusz
* @property name
* @property backlog the amount of connections to accept
- * @property databasePath
* @property address IPv4 address
* @property port
+ * @property postgresql Postgresql port
+ * @property username Postgresql user
+ * @property password Postgresql password
+ * @property database Postgresql database
+ * @property topic Kafka topic
+ * @property kafka Kafka port
*/
@Serializable
public data class Config(
val name: String = "",
var backlog: Int = 0,
val address: String = "",
- val port: Int = 8080,
- val postgresql: Int = 5342,
+ val port: Int = 0,
+ val postgresql: Int = 0,
val username : String = "",
val password : String = "",
- val database: String = ""
+ val database: String = "",
+ val topic : String = "",
+ val kafka: Int = 0,
){
public companion object{
public var input: InputStream? = null
public var output: OutputStream? = null
public var connection : Connection? = null
+ public var kafka : Kafka? = null
+ public var database : PostgresqlDB? = null
public var socket: Socket? = null
@@ -57,9 +65,26 @@ public data class Config(
public fun getConfigWriter() : OutputStream? {
return output
}
+
+ public fun setKafkaInstance(kafka : Kafka) {
+ this.kafka = kafka
+ }
+
+ public fun getKafkaInstance() : Kafka? {
+ return this.kafka
+ }
+
+ public fun setDB(db : PostgresqlDB){
+ this.database = db
+ }
+
+ public fun getDB() : PostgresqlDB?{
+ return this.database
+ }
}
}
/**
+ * @author Mateusz
* Reads `config.json` into Config data class.
*/
public class ConfigReader {
diff --git a/opendc-common/src/main/kotlin/org/opendc/common/utils/Kafka.kt b/opendc-common/src/main/kotlin/org/opendc/common/utils/Kafka.kt
new file mode 100644
index 00000000..48590d9f
--- /dev/null
+++ b/opendc-common/src/main/kotlin/org/opendc/common/utils/Kafka.kt
@@ -0,0 +1,41 @@
+package org.opendc.common.utils
+import org.apache.kafka.clients.producer.KafkaProducer
+import org.apache.kafka.clients.producer.Producer
+import org.apache.kafka.clients.producer.ProducerRecord
+import org.opendc.common.ProtobufMetrics
+
+import java.util.*
+
+public class Kafka (
+ private val topic : String,
+ address : String,
+ port : Int,
+) {
+ private val servers : String = "$address:$port"
+ private var properties: Properties? = null
+ private var producer: Producer<String, ProtobufMetrics.ProtoExport>? = null
+
+ init {
+ properties = Properties()
+ properties?.put("bootstrap.servers", servers)
+ properties?.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer")
+ properties?.put("value.serializer", "io.confluent.kafka.serializers.protobuf.KafkaProtobufSerializer")
+ properties?.put("schema.registry.url", "http://localhost:8081")
+ properties?.put("auto.register.schemas", "true")
+
+ try {
+ producer = KafkaProducer(properties)
+ } catch (e: Exception){
+ println("${e.message}")
+ }
+ }
+
+ public fun getProducer() : Producer<String, ProtobufMetrics.ProtoExport>? {
+ return this.producer
+ }
+
+ public fun send(value : ProtobufMetrics.ProtoExport){
+ producer?.send(ProducerRecord(this.topic, value))
+ }
+
+} \ No newline at end of file
diff --git a/opendc-common/src/main/kotlin/org/opendc/common/utils/PostgresqlDB.kt b/opendc-common/src/main/kotlin/org/opendc/common/utils/PostgresqlDB.kt
index 3dc7a0e4..69314ef3 100644
--- a/opendc-common/src/main/kotlin/org/opendc/common/utils/PostgresqlDB.kt
+++ b/opendc-common/src/main/kotlin/org/opendc/common/utils/PostgresqlDB.kt
@@ -4,25 +4,40 @@ import java.sql.Connection
import java.sql.DriverManager
import java.sql.SQLException
-public class PostgresqlDB {
- public var connection : Connection? = null
- public var dbUrl : String = ""
- public var user : String = ""
- public var password : String = ""
+/**
+ * Represents the Postgresql database.
+ * On setup cleans the entire database and creates empty tables.
+ *
+ * @author Mateusz
+ *
+ * @param address ipv4 address
+ * @param port postgres post
+ * @param dbName database name
+ * @param user
+ * @param password
+ */
+public class PostgresqlDB(
+ address : String,
+ port : Int,
+ dbName : String,
+ private var user : String,
+ private var password : String,
+) {
+ private var connection : Connection? = null
+ private var dbUrl : String = ""
- public fun setupDatabase(address : String, port : Int, dbUser : String, dbPassword : String, db : String){
- dbUrl = "jdbc:postgresql://$address:$port/$db"
- user = dbUser
- password = dbPassword
+ init {
+ dbUrl = "jdbc:postgresql://$address:$port/$dbName"
println(dbUrl)
try {
- connection = DriverManager.getConnection(dbUrl, dbUser, dbPassword)
+ connection = DriverManager.getConnection(dbUrl, user, password)
+ clear()
+ setup()
} catch (e: SQLException) {
print("${e.message}")
}
}
-
- public fun create(){
+ public fun setup(){
val CREATE_TABLE = """
CREATE TABLE metrics (
id SERIAL PRIMARY KEY,
diff --git a/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/KafkaComputeMonitor.kt b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/KafkaComputeMonitor.kt
new file mode 100644
index 00000000..d0be10db
--- /dev/null
+++ b/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/telemetry/KafkaComputeMonitor.kt
@@ -0,0 +1,50 @@
+package org.opendc.compute.simulator.telemetry
+
+
+import com.fasterxml.jackson.databind.ObjectMapper
+import org.opendc.common.utils.Config
+import org.opendc.common.utils.Kafka
+import org.opendc.common.ProtobufMetrics
+
+import org.opendc.compute.simulator.telemetry.table.host.HostTableReader
+
+/**
+ * @author Mateusz
+ * This class logs data from the simulator into Kafka.
+ */
+public class KafkaComputeMonitor: ComputeMonitor {
+ private val metrics : MonitoringMetrics = MonitoringMetrics()
+ private val kafka : Kafka? = Config.getKafkaInstance()
+
+ @Override
+ override fun record(reader: HostTableReader) {
+ metrics.id += 1
+ metrics.timestamp = reader.timestamp.toEpochMilli()
+ metrics.tasksActive = reader.tasksActive
+ metrics.clusterName = reader.hostInfo.clusterName
+
+ try{
+ val packet = ProtobufMetrics.ProtoExport.newBuilder()
+ .setId(metrics.id)
+ .setTasksactive(metrics.tasksActive)
+ .build()
+ kafka?.send(packet)
+ }
+
+ catch(e: Exception){
+ println("${e.message}")
+ }
+ }
+
+}
+
+/**
+ * @author Mateusz
+ * This serves as editable data class for ObjectMapper().
+ */
+public class MonitoringMetrics {
+ public var id: Int = 0
+ public var timestamp: Long = 0
+ public var tasksActive : Int = 0
+ public var clusterName: String = ""
+}
diff --git a/opendc-demo/build.gradle.kts b/opendc-demo/build.gradle.kts
index 02972f44..d5a84120 100644
--- a/opendc-demo/build.gradle.kts
+++ b/opendc-demo/build.gradle.kts
@@ -28,9 +28,5 @@ plugins {
}
dependencies {
- // Source: https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients
- implementation("org.apache.kafka:kafka-clients:4.1.1")
- implementation(libs.jackson.core)
implementation(project(mapOf("path" to "::opendc-compute:opendc-compute-simulator")))
-
}
diff --git a/opendc-demo/src/main/kotlin/org/opendc/demo/DemoComputeMonitor.kt b/opendc-demo/src/main/kotlin/org/opendc/demo/DemoComputeMonitor.kt
deleted file mode 100644
index f59f90a1..00000000
--- a/opendc-demo/src/main/kotlin/org/opendc/demo/DemoComputeMonitor.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.opendc.demo
-
-import com.fasterxml.jackson.databind.ObjectMapper
-import org.apache.kafka.clients.producer.ProducerRecord
-import org.opendc.compute.simulator.telemetry.ComputeMonitor
-import org.opendc.compute.simulator.telemetry.table.host.HostTableReader
-import java.time.Instant
-
-public class DemoComputeMonitor: ComputeMonitor {
- public val metrics : MonitoringMetrics = MonitoringMetrics()
-
- @Override
- override fun record(reader: HostTableReader) {
- metrics.timestamp = reader.timestamp.toEpochMilli()
- metrics.tasksActive = reader.tasksActive
- metrics.clusterName = reader.hostInfo.clusterName
-
- try{
- val objectMapper = ObjectMapper()
- val jsonBytes = objectMapper.writeValueAsBytes(metrics)
- println(metrics.clusterName)
- }
-
- catch(e: Exception){
- println("${e.message}")
- }
- }
-
-}
-public class MonitoringMetrics {
- public var timestamp: Long = 0
- public var tasksActive : Int = 0
- public var cpuUsage : Double = 0.0
- public var cpuUtilisation: Double = 0.0
- public var cpuActiveTime : Long = 0
- public var cpuIdleTime: Long = 0
- public var cpuLostTime: Long = 0
- public var energyUsage: Double = 0.0
- public var uptime: Long = 0
- public var powerDraw: Double = 0.0
- public var clusterName: String = ""
-}
diff --git a/opendc-demo/src/main/kotlin/org/opendc/demo/RunRequest.kt b/opendc-demo/src/main/kotlin/org/opendc/demo/RunRequest.kt
index e24a0af5..c4dfb7ca 100644
--- a/opendc-demo/src/main/kotlin/org/opendc/demo/RunRequest.kt
+++ b/opendc-demo/src/main/kotlin/org/opendc/demo/RunRequest.kt
@@ -23,7 +23,5 @@
package org.opendc.demo
public fun runRequest(request: String) {
- // https://github.com/am-i-helpful/opendc/blob/master/opendc-oda/opendc-oda-experiments/src/main/kotlin/org/opendc/oda/experimentrunner/ODAComputeMonitor.kt
- // Do this here
println("The request is $request\n")
}
diff --git a/opendc-experiments/opendc-experiments-base/build.gradle.kts b/opendc-experiments/opendc-experiments-base/build.gradle.kts
index bac04854..76de6a3c 100644
--- a/opendc-experiments/opendc-experiments-base/build.gradle.kts
+++ b/opendc-experiments/opendc-experiments-base/build.gradle.kts
@@ -85,4 +85,6 @@ distributions {
}
repositories {
mavenCentral()
+ // @Mateusz crucial to include this for kafka proto
+ maven(url = "https://packages.confluent.io/maven/")
}
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt
index 874f5654..96071833 100644
--- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentCli.kt
@@ -30,6 +30,7 @@ import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.types.file
import org.opendc.common.utils.Config
import org.opendc.common.utils.ConfigReader
+import org.opendc.common.utils.Kafka
import org.opendc.common.utils.PostgresqlDB
import org.opendc.experiments.base.experiment.getExperiment
import java.io.File
@@ -49,6 +50,7 @@ public fun main(args: Array<String>) {
/**
+ * @author Mateusz
* Opens a client socket from `config`, but otherwise works as before.
*/
internal class ExperimentCommand : CliktCommand(name = "experiment") {
@@ -68,6 +70,7 @@ internal class ExperimentCommand : CliktCommand(name = "experiment") {
try {
clientSocket = Socket(config.address, config.port)
Config.setConfigSocket(clientSocket)
+ Config.setKafkaInstance(Kafka(config.topic, config.address, config.kafka))
val experiment = getExperiment(experimentPath)
runExperiment(experiment)
@@ -81,6 +84,7 @@ internal class ExperimentCommand : CliktCommand(name = "experiment") {
}
/**
+ * @author Mateusz
* Creates a server socket and database connection from `config`.
*/
internal class ExperimentListener: CliktCommand(name = "listener") {
@@ -92,14 +96,11 @@ internal class ExperimentListener: CliktCommand(name = "listener") {
val configReader = ConfigReader()
var serverSocket: ServerSocket? = null
val config = configReader.read(configPath)
- val database = PostgresqlDB()
- val inetAddress = InetAddress.getByName(config.address)
+ Config.setDB(PostgresqlDB(config.address, config.postgresql, config.database, config.username, config.password))
try {
+ val inetAddress = InetAddress.getByName(config.address)
serverSocket = ServerSocket(config.port, config.backlog, inetAddress)
- database.setupDatabase(config.address, config.postgresql, config.username, config.password, config.database)
- database.clear()
- database.create()
runListener(serverSocket)
} catch (e: IOException) {
println("${e.message}")
@@ -107,9 +108,4 @@ internal class ExperimentListener: CliktCommand(name = "listener") {
serverSocket?.close()
}
}
-}
-
-
-
-
-
+} \ No newline at end of file
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt
index 9d1f7374..9fee6cf9 100644
--- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ExperimentRunner.kt
@@ -65,6 +65,7 @@ public fun runExperiment(experiment: List<Scenario>) {
}
/**
+ * @author Mateusz
* Accepts a (single) connection and listens for requests.
* @param socket The socket to listen to.
*/
@@ -72,9 +73,6 @@ public fun runListener(socket: ServerSocket) {
var client : Socket? = null
try {
client = socket.accept()
- // here you should create another thread listening for sever-Kafka-client
- // communication, and to store the incoming results into Postgresql
-
Config.setConfigSocket(client)
val request = ByteArray(1024)
diff --git a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt
index f33b6da8..ab25ef25 100644
--- a/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt
+++ b/opendc-experiments/opendc-experiments-base/src/main/kotlin/org/opendc/experiments/base/runner/ScenarioRunner.kt
@@ -30,11 +30,8 @@ import org.opendc.compute.simulator.provisioner.setupComputeService
import org.opendc.compute.simulator.provisioner.setupHosts
import org.opendc.compute.simulator.scheduler.ComputeScheduler
import org.opendc.compute.simulator.service.ComputeService
-import org.opendc.compute.simulator.telemetry.parquet.ComputeExportConfig
-import org.opendc.compute.simulator.telemetry.parquet.ParquetComputeMonitor
-import org.opendc.compute.simulator.telemetry.parquet.withGpuColumns
import org.opendc.compute.topology.clusterTopology
-import org.opendc.demo.DemoComputeMonitor
+import org.opendc.compute.simulator.telemetry.KafkaComputeMonitor
import org.opendc.experiments.base.experiment.Scenario
import org.opendc.experiments.base.experiment.specs.allocation.TimeShiftAllocationPolicySpec
import org.opendc.experiments.base.experiment.specs.allocation.createComputeScheduler
@@ -194,15 +191,15 @@ public fun addExportModel(
) {
/*
- * @Mateusz
- * Here is the entry point to DemoComputeMonitor().
+ * @author Mateusz
+ * Here is the entry point to KafkaComputeMonitor().
* With this setting, the simulator no longer writes to parquet files.
* To get back the original code, refer to https://github.com/atlarge-research/opendc
* */
provisioner.runStep(
registerComputeMonitor(
serviceDomain,
- DemoComputeMonitor(),
+ KafkaComputeMonitor(),
Duration.ofSeconds(scenario.exportModelSpec.exportInterval),
startTime,
scenario.exportModelSpec.filesToExportDict,
diff --git a/opendc-web/build.gradle.kts b/opendc-web/build.gradle.kts
deleted file mode 100644
index 47b19763..00000000
--- a/opendc-web/build.gradle.kts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Interactive web interface for OpenDC"
-
-subprojects {
- group = "org.opendc.web"
-}
diff --git a/opendc-web/opendc-web-client/build.gradle.kts b/opendc-web/opendc-web-client/build.gradle.kts
deleted file mode 100644
index 55228ef9..00000000
--- a/opendc-web/opendc-web-client/build.gradle.kts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Client for the OpenDC web API"
-
-// Build configuration
-plugins {
- `kotlin-library-conventions`
-}
-
-dependencies {
- api(projects.opendcWeb.opendcWebProto)
- implementation(libs.jackson.module.kotlin)
- implementation(libs.jackson.datatype.jsr310)
- implementation(libs.jakarta.validation)
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt
deleted file mode 100644
index a34c7864..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/OpenDCClient.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client
-
-import org.opendc.web.client.auth.AuthController
-import org.opendc.web.client.transport.HttpTransportClient
-import org.opendc.web.client.transport.TransportClient
-import java.net.URI
-
-/**
- * Client implementation for the user-facing OpenDC REST API (version 2).
- *
- * @param client Low-level client for managing the underlying transport.
- */
-public class OpenDCClient(client: TransportClient) {
- /**
- * Construct a new [OpenDCClient].
- *
- * @param baseUrl The base url of the API.
- * @param auth Helper class for managing authentication.
- */
- public constructor(baseUrl: URI, auth: AuthController? = null) : this(HttpTransportClient(baseUrl, auth))
-
- /**
- * A resource for the available projects.
- */
- public val projects: ProjectResource = ProjectResource(client)
-
- /**
- * A resource for the topologies available to the user.
- */
- public val topologies: TopologyResource = TopologyResource(client)
-
- /**
- * A resource for the portfolios available to the user.
- */
- public val portfolios: PortfolioResource = PortfolioResource(client)
-
- /**
- * A resource for the scenarios available to the user.
- */
- public val scenarios: ScenarioResource = ScenarioResource(client)
-
- /**
- * A resource for the available schedulers.
- */
- public val schedulers: SchedulerResource = SchedulerResource(client)
-
- /**
- * A resource for the available workload traces.
- */
- public val traces: TraceResource = TraceResource(client)
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/PortfolioResource.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/PortfolioResource.kt
deleted file mode 100644
index f0e49973..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/PortfolioResource.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client
-
-import org.opendc.web.client.internal.delete
-import org.opendc.web.client.internal.get
-import org.opendc.web.client.internal.post
-import org.opendc.web.client.transport.TransportClient
-import org.opendc.web.proto.user.Portfolio
-
-/**
- * A resource representing the portfolios available to the user.
- */
-public class PortfolioResource internal constructor(private val client: TransportClient) {
- /**
- * List all portfolios that belong to the specified [project].
- */
- public fun getAll(project: Long): List<Portfolio> = client.get("projects/$project/portfolios") ?: emptyList()
-
- /**
- * Obtain the portfolio for [project] with [number].
- */
- public fun get(
- project: Long,
- number: Int,
- ): Portfolio? = client.get("projects/$project/portfolios/$number")
-
- /**
- * Create a new portfolio for [project] with the specified [request].
- */
- public fun create(
- project: Long,
- request: Portfolio.Create,
- ): Portfolio {
- return checkNotNull(client.post("projects/$project/portfolios", request))
- }
-
- /**
- * Delete the portfolio for [project] with [index].
- */
- public fun delete(
- project: Long,
- index: Int,
- ): Portfolio {
- return requireNotNull(client.delete("projects/$project/portfolios/$index")) { "Unknown portfolio $index" }
- }
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ProjectResource.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ProjectResource.kt
deleted file mode 100644
index 579d0d66..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ProjectResource.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client
-
-import org.opendc.web.client.internal.delete
-import org.opendc.web.client.internal.get
-import org.opendc.web.client.internal.post
-import org.opendc.web.client.transport.TransportClient
-import org.opendc.web.proto.user.Project
-
-/**
- * A resource representing the projects available to the user.
- */
-public class ProjectResource internal constructor(private val client: TransportClient) {
- /**
- * List all projects available to the user.
- */
- public fun getAll(): List<Project> = client.get("projects") ?: emptyList()
-
- /**
- * Obtain the project with [id].
- */
- public fun get(id: Long): Project? = client.get("projects/$id")
-
- /**
- * Create a new project.
- */
- public fun create(name: String): Project = checkNotNull(client.post("projects", Project.Create(name)))
-
- /**
- * Delete the project with the specified [id].
- */
- public fun delete(id: Long): Project = requireNotNull(client.delete("projects/$id")) { "Unknown project $id" }
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ScenarioResource.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ScenarioResource.kt
deleted file mode 100644
index d43515a9..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/ScenarioResource.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client
-
-import org.opendc.web.client.internal.delete
-import org.opendc.web.client.internal.get
-import org.opendc.web.client.internal.post
-import org.opendc.web.client.transport.TransportClient
-import org.opendc.web.proto.user.Scenario
-
-/**
- * A resource representing the scenarios available to the user.
- */
-public class ScenarioResource internal constructor(private val client: TransportClient) {
- /**
- * List all scenarios that belong to the specified [project].
- */
- public fun getAll(project: Long): List<Scenario> = client.get("projects/$project/scenarios") ?: emptyList()
-
- /**
- * List all scenarios that belong to the specified [portfolioNumber].
- */
- public fun getAll(
- project: Long,
- portfolioNumber: Int,
- ): List<Scenario> = client.get("projects/$project/portfolios/$portfolioNumber/scenarios") ?: emptyList()
-
- /**
- * Obtain the scenario for [project] with [index].
- */
- public fun get(
- project: Long,
- index: Int,
- ): Scenario? = client.get("projects/$project/scenarios/$index")
-
- /**
- * Create a new scenario for [portfolio][portfolioNumber] with the specified [request].
- */
- public fun create(
- project: Long,
- portfolioNumber: Int,
- request: Scenario.Create,
- ): Scenario {
- return checkNotNull(client.post("projects/$project/portfolios/$portfolioNumber", request))
- }
-
- /**
- * Delete the scenario for [project] with [index].
- */
- public fun delete(
- project: Long,
- index: Int,
- ): Scenario {
- return requireNotNull(client.delete("projects/$project/scenarios/$index")) { "Unknown scenario $index" }
- }
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/SchedulerResource.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/SchedulerResource.kt
deleted file mode 100644
index 43b72d88..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/SchedulerResource.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client
-
-import org.opendc.web.client.internal.get
-import org.opendc.web.client.transport.TransportClient
-
-/**
- * A resource representing the schedulers available in the OpenDC instance.
- */
-public class SchedulerResource internal constructor(private val client: TransportClient) {
- /**
- * List all schedulers available.
- */
- public fun getAll(): List<String> = client.get("schedulers") ?: emptyList()
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TopologyResource.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TopologyResource.kt
deleted file mode 100644
index 34f5ea1b..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TopologyResource.kt
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client
-
-import org.opendc.web.client.internal.delete
-import org.opendc.web.client.internal.get
-import org.opendc.web.client.internal.post
-import org.opendc.web.client.internal.put
-import org.opendc.web.client.transport.TransportClient
-import org.opendc.web.proto.user.Topology
-
-/**
- * A resource representing the topologies available to the user.
- */
-public class TopologyResource internal constructor(private val client: TransportClient) {
- /**
- * List all topologies that belong to the specified [project].
- */
- public fun getAll(project: Long): List<Topology> = client.get("projects/$project/topologies") ?: emptyList()
-
- /**
- * Obtain the topology for [project] with [index].
- */
- public fun get(
- project: Long,
- index: Int,
- ): Topology? = client.get("projects/$project/topologies/$index")
-
- /**
- * Create a new topology for [project] with [request].
- */
- public fun create(
- project: Long,
- request: Topology.Create,
- ): Topology {
- return checkNotNull(client.post("projects/$project/topologies", request))
- }
-
- /**
- * Update the topology with [index] for [project] using the specified [request].
- */
- public fun update(
- project: Long,
- index: Int,
- request: Topology.Update,
- ): Topology? {
- return client.put("projects/$project/topologies/$index", request)
- }
-
- /**
- * Delete the topology for [project] with [index].
- */
- public fun delete(
- project: Long,
- index: Long,
- ): Topology {
- return requireNotNull(client.delete("projects/$project/topologies/$index")) { "Unknown topology $index" }
- }
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TraceResource.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TraceResource.kt
deleted file mode 100644
index b4a8c089..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/TraceResource.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client
-
-import org.opendc.web.client.internal.get
-import org.opendc.web.client.transport.TransportClient
-import org.opendc.web.proto.Trace
-
-/**
- * A resource representing the workload traces available in the OpenDC instance.
- */
-public class TraceResource internal constructor(private val client: TransportClient) {
- /**
- * List all workload traces available.
- */
- public fun getAll(): List<Trace> = client.get("traces") ?: emptyList()
-
- /**
- * Obtain the workload trace with the specified [id].
- */
- public fun get(id: Long): Trace? = client.get("traces/$id")
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/AuthController.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/AuthController.kt
deleted file mode 100644
index a4c66f55..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/AuthController.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.auth
-
-import java.net.http.HttpRequest
-
-/**
- * Helper interface for managing API authentication.
- */
-public interface AuthController {
- /**
- * Inject the authorization token into the specified [request].
- */
- public fun injectToken(request: HttpRequest.Builder)
-
- /**
- * Refresh the current auth token.
- */
- public fun refreshToken()
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/OpenIdAuthController.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/OpenIdAuthController.kt
deleted file mode 100644
index 707dc138..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/auth/OpenIdAuthController.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.auth
-
-import com.fasterxml.jackson.databind.DeserializationFeature
-import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
-import com.fasterxml.jackson.module.kotlin.readValue
-import org.opendc.web.client.internal.OAuthTokenRequest
-import org.opendc.web.client.internal.OAuthTokenResponse
-import org.opendc.web.client.internal.OpenIdConfiguration
-import java.net.URI
-import java.net.http.HttpClient
-import java.net.http.HttpRequest
-import java.net.http.HttpResponse
-
-/**
- * An [AuthController] for OpenID Connect protected APIs.
- */
-public class OpenIdAuthController(
- private val domain: String,
- private val clientId: String,
- private val clientSecret: String,
- private val audience: String = "https://api.opendc.org/v2/",
- private val client: HttpClient = HttpClient.newHttpClient(),
-) : AuthController {
- /**
- * The Jackson object mapper to convert messages from/to JSON.
- */
- private val mapper =
- jacksonObjectMapper()
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
-
- /**
- * The cached [OpenIdConfiguration].
- */
- private val openidConfig: OpenIdConfiguration
- get() {
- var openidConfig = localOpenidConfig
- if (openidConfig == null) {
- openidConfig = requestConfig()
- localOpenidConfig = openidConfig
- }
-
- return openidConfig
- }
- private var localOpenidConfig: OpenIdConfiguration? = null
-
- /**
- * The cached OAuth token.
- */
- private var localToken: OAuthTokenResponse? = null
-
- override fun injectToken(request: HttpRequest.Builder) {
- var token = localToken
- if (token == null) {
- token = requestToken()
- localToken = token
- }
-
- request.header("Authorization", "Bearer ${token.accessToken}")
- }
-
- /**
- * Refresh the current access token.
- */
- override fun refreshToken() {
- val refreshToken = localToken?.refreshToken
- if (refreshToken == null) {
- requestToken()
- return
- }
-
- localToken = refreshToken(openidConfig, refreshToken)
- }
-
- /**
- * Request the OpenID configuration from the chosen auth domain
- */
- private fun requestConfig(): OpenIdConfiguration {
- val request =
- HttpRequest.newBuilder(URI("https://$domain/.well-known/openid-configuration"))
- .GET()
- .build()
- val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream())
- return mapper.readValue(response.body())
- }
-
- /**
- * Request the auth token from the server.
- */
- private fun requestToken(openidConfig: OpenIdConfiguration): OAuthTokenResponse {
- val body = OAuthTokenRequest.ClientCredentials(audience, clientId, clientSecret)
- val request =
- HttpRequest.newBuilder(openidConfig.tokenEndpoint)
- .header("Content-Type", "application/json")
- .POST(HttpRequest.BodyPublishers.ofByteArray(mapper.writeValueAsBytes(body)))
- .build()
- val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream())
- return mapper.readValue(response.body())
- }
-
- /**
- * Helper method to refresh the auth token.
- */
- private fun refreshToken(
- openidConfig: OpenIdConfiguration,
- refreshToken: String,
- ): OAuthTokenResponse {
- val body = OAuthTokenRequest.RefreshToken(refreshToken, clientId, clientSecret)
- val request =
- HttpRequest.newBuilder(openidConfig.tokenEndpoint)
- .header("Content-Type", "application/json")
- .POST(HttpRequest.BodyPublishers.ofByteArray(mapper.writeValueAsBytes(body)))
- .build()
- val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream())
- return mapper.readValue(response.body())
- }
-
- /**
- * Fetch a new access token.
- */
- private fun requestToken(): OAuthTokenResponse {
- val token = requestToken(openidConfig)
- localToken = token
- return token
- }
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/ClientUtils.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/ClientUtils.kt
deleted file mode 100644
index 1ffaa602..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/ClientUtils.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.internal
-
-import com.fasterxml.jackson.core.type.TypeReference
-import org.opendc.web.client.transport.TransportClient
-
-/**
- * Perform a GET request for resource at [path] and convert to type [T].
- */
-internal inline fun <reified T> TransportClient.get(path: String): T? {
- return get(path, object : TypeReference<T>() {})
-}
-
-/**
- * Perform a POST request for resource at [path] and convert to type [T].
- */
-internal inline fun <B, reified T> TransportClient.post(
- path: String,
- body: B,
-): T? {
- return post(path, body, object : TypeReference<T>() {})
-}
-
-/**
- * Perform a PUT request for resource at [path] and convert to type [T].
- */
-internal inline fun <B, reified T> TransportClient.put(
- path: String,
- body: B,
-): T? {
- return put(path, body, object : TypeReference<T>() {})
-}
-
-/**
- * Perform a DELETE request for resource at [path] and convert to type [T].
- */
-internal inline fun <reified T> TransportClient.delete(path: String): T? {
- return delete(path, object : TypeReference<T>() {})
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenRequest.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenRequest.kt
deleted file mode 100644
index 1bb06c8f..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenRequest.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.internal
-
-import com.fasterxml.jackson.annotation.JsonProperty
-import com.fasterxml.jackson.annotation.JsonSubTypes
-import com.fasterxml.jackson.annotation.JsonTypeInfo
-
-/**
- * Token request sent to the OAuth server.
- */
-@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "grant_type")
-@JsonSubTypes(
- value = [
- JsonSubTypes.Type(value = OAuthTokenRequest.ClientCredentials::class, name = "client_credentials"),
- JsonSubTypes.Type(value = OAuthTokenRequest.RefreshToken::class, name = "refresh_token"),
- ],
-)
-internal sealed class OAuthTokenRequest {
- /**
- * Client credentials grant for OAuth2
- */
- data class ClientCredentials(
- val audience: String,
- @JsonProperty("client_id")
- val clientId: String,
- @JsonProperty("client_secret")
- val clientSecret: String,
- ) : OAuthTokenRequest()
-
- /**
- * Refresh token grant for OAuth2.
- */
- data class RefreshToken(
- @JsonProperty("refresh_token")
- val refreshToken: String,
- @JsonProperty("client_id")
- val clientId: String,
- @JsonProperty("client_secret")
- val clientSecret: String,
- ) : OAuthTokenRequest()
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenResponse.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenResponse.kt
deleted file mode 100644
index 76fe007c..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OAuthTokenResponse.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.internal
-
-import com.fasterxml.jackson.annotation.JsonProperty
-
-/**
- * Token response from the OAuth server.
- */
-internal data class OAuthTokenResponse(
- @JsonProperty("access_token")
- val accessToken: String,
- @JsonProperty("refresh_token")
- val refreshToken: String? = null,
- @JsonProperty("token_type")
- val tokenType: String,
- val scope: String = "",
- @JsonProperty("expires_in")
- val expiresIn: Long,
-)
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OpenIdConfiguration.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OpenIdConfiguration.kt
deleted file mode 100644
index eac1607e..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/internal/OpenIdConfiguration.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.internal
-
-import com.fasterxml.jackson.annotation.JsonProperty
-import java.net.URI
-
-/**
- * OpenID configuration exposed by the auth server.
- */
-internal data class OpenIdConfiguration(
- val issuer: String,
- @JsonProperty("authorization_endpoint")
- val authorizationEndpoint: URI,
- @JsonProperty("token_endpoint")
- val tokenEndpoint: URI,
- @JsonProperty("userinfo_endpoint")
- val userInfoEndpoint: URI,
- @JsonProperty("jwks_uri")
- val jwksUri: URI,
- @JsonProperty("scopes_supported")
- val scopesSupported: Set<String>,
-)
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/JobResource.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/JobResource.kt
deleted file mode 100644
index e72f703c..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/JobResource.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.runner
-
-import org.opendc.web.client.internal.get
-import org.opendc.web.client.internal.post
-import org.opendc.web.client.transport.TransportClient
-import org.opendc.web.proto.runner.Job
-
-/**
- * A resource representing the available simulation jobs for the runner.
- */
-public class JobResource internal constructor(private val client: TransportClient) {
- /**
- * Query the pending jobs.
- */
- public fun queryPending(): List<Job> = client.get("jobs") ?: emptyList()
-
- /**
- * Obtain the job with [id].
- */
- public fun get(id: Long): Job? = client.get("jobs/$id")
-
- /**
- * Update the job with [id].
- */
- public fun update(
- id: Long,
- update: Job.Update,
- ): Job? = client.post("jobs/$id", update)
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt
deleted file mode 100644
index 98785a55..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/runner/OpenDCRunnerClient.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.runner
-
-import org.opendc.web.client.SchedulerResource
-import org.opendc.web.client.TraceResource
-import org.opendc.web.client.auth.AuthController
-import org.opendc.web.client.transport.HttpTransportClient
-import org.opendc.web.client.transport.TransportClient
-import java.net.URI
-
-/**
- * Client implementation for the runner-facing OpenDC REST API (version 2).
- *
- * @param client Low-level client for managing the underlying transport.
- */
-public class OpenDCRunnerClient(client: TransportClient) {
- /**
- * Construct a new [OpenDCRunnerClient].
- *
- * @param baseUrl The base url of the API.
- * @param auth Helper class for managing authentication.
- */
- public constructor(baseUrl: URI, auth: AuthController? = null) : this(HttpTransportClient(baseUrl, auth))
-
- /**
- * A resource for the available simulation jobs.
- */
- public val jobs: JobResource = JobResource(client)
-
- /**
- * A resource for the available schedulers.
- */
- public val schedulers: SchedulerResource = SchedulerResource(client)
-
- /**
- * A resource for the available workload traces.
- */
- public val traces: TraceResource = TraceResource(client)
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt
deleted file mode 100644
index f6dca4d1..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/HttpTransportClient.kt
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.transport
-
-import com.fasterxml.jackson.core.type.TypeReference
-import com.fasterxml.jackson.databind.DeserializationFeature
-import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
-import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
-import org.opendc.web.client.auth.AuthController
-import java.net.URI
-import java.net.http.HttpClient
-import java.net.http.HttpRequest
-import java.net.http.HttpResponse
-import java.nio.file.Paths
-
-/**
- * A [TransportClient] that accesses the OpenDC API over HTTP.
- *
- * @param baseUrl The base url of the API.
- * @param auth Helper class for managing authentication.
- * @param client The HTTP client to use.
- */
-public class HttpTransportClient(
- private val baseUrl: URI,
- private val auth: AuthController?,
- private val client: HttpClient = HttpClient.newHttpClient(),
-) : TransportClient {
- /**
- * The Jackson object mapper to convert messages from/to JSON.
- */
- private val mapper =
- jacksonObjectMapper()
- .registerModule(JavaTimeModule())
- .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
-
- /**
- * Obtain a resource at [path] of [targetType].
- */
- override fun <T> get(
- path: String,
- targetType: TypeReference<T>,
- ): T? {
- val request =
- HttpRequest.newBuilder(buildUri(path))
- .GET()
- .also { auth?.injectToken(it) }
- .build()
- val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream())
-
- return when (val code = response.statusCode()) {
- in 200..299 -> mapper.readValue(response.body(), targetType)
- 401 -> {
- val auth = auth
- if (auth != null) {
- auth.refreshToken()
- get(path, targetType)
- } else {
- throw IllegalStateException("Authorization required")
- }
- }
- 404 -> null
- else -> throw IllegalStateException("Invalid response $code")
- }
- }
-
- /**
- * Update a resource at [path] of [targetType].
- */
- override fun <B, T> post(
- path: String,
- body: B,
- targetType: TypeReference<T>,
- ): T? {
- val request =
- HttpRequest.newBuilder(buildUri(path))
- .POST(HttpRequest.BodyPublishers.ofByteArray(mapper.writeValueAsBytes(body)))
- .header("Content-Type", "application/json")
- .also { auth?.injectToken(it) }
- .build()
- val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream())
-
- return when (val code = response.statusCode()) {
- in 200..299 -> mapper.readValue(response.body(), targetType)
- 401 -> {
- val auth = auth
- if (auth != null) {
- auth.refreshToken()
- post(path, body, targetType)
- } else {
- throw IllegalStateException("Authorization required")
- }
- }
- 404 -> null
- else -> throw IllegalStateException("Invalid response $code")
- }
- }
-
- /**
- * Replace a resource at [path] of [targetType].
- */
- override fun <B, T> put(
- path: String,
- body: B,
- targetType: TypeReference<T>,
- ): T? {
- val request =
- HttpRequest.newBuilder(buildUri(path))
- .PUT(HttpRequest.BodyPublishers.ofByteArray(mapper.writeValueAsBytes(body)))
- .header("Content-Type", "application/json")
- .also { auth?.injectToken(it) }
- .build()
- val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream())
-
- return when (val code = response.statusCode()) {
- in 200..299 -> mapper.readValue(response.body(), targetType)
- 401 -> {
- val auth = auth
- if (auth != null) {
- auth.refreshToken()
- put(path, body, targetType)
- } else {
- throw IllegalStateException("Authorization required")
- }
- }
- 404 -> null
- else -> throw IllegalStateException("Invalid response $code")
- }
- }
-
- /**
- * Delete a resource at [path] of [targetType].
- */
- override fun <T> delete(
- path: String,
- targetType: TypeReference<T>,
- ): T? {
- val request =
- HttpRequest.newBuilder(buildUri(path))
- .DELETE()
- .also { auth?.injectToken(it) }
- .build()
- val response = client.send(request, HttpResponse.BodyHandlers.ofInputStream())
-
- return when (val code = response.statusCode()) {
- in 200..299 -> mapper.readValue(response.body(), targetType)
- 401 -> {
- val auth = auth
- if (auth != null) {
- auth.refreshToken()
- delete(path, targetType)
- } else {
- throw IllegalStateException("Authorization required")
- }
- }
- 404 -> null
- else -> throw IllegalStateException("Invalid response $code")
- }
- }
-
- /**
- * Build the absolute [URI] to which the request should be sent.
- */
- private fun buildUri(path: String): URI = baseUrl.resolve(Paths.get(baseUrl.path, path).toString())
-}
diff --git a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/TransportClient.kt b/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/TransportClient.kt
deleted file mode 100644
index ebf3402f..00000000
--- a/opendc-web/opendc-web-client/src/main/kotlin/org/opendc/web/client/transport/TransportClient.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.client.transport
-
-import com.fasterxml.jackson.core.type.TypeReference
-
-/**
- * Low-level interface for dealing with the transport layer of the API.
- */
-public interface TransportClient {
- /**
- * Obtain a resource at [path] of [targetType].
- */
- public fun <T> get(
- path: String,
- targetType: TypeReference<T>,
- ): T?
-
- /**
- * Update a resource at [path] of [targetType].
- */
- public fun <B, T> post(
- path: String,
- body: B,
- targetType: TypeReference<T>,
- ): T?
-
- /**
- * Replace a resource at [path] of [targetType].
- */
- public fun <B, T> put(
- path: String,
- body: B,
- targetType: TypeReference<T>,
- ): T?
-
- /**
- * Delete a resource at [path] of [targetType].
- */
- public fun <T> delete(
- path: String,
- targetType: TypeReference<T>,
- ): T?
-}
diff --git a/opendc-web/opendc-web-proto/build.gradle.kts b/opendc-web/opendc-web-proto/build.gradle.kts
deleted file mode 100644
index 9b307655..00000000
--- a/opendc-web/opendc-web-proto/build.gradle.kts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Web communication protocol for OpenDC"
-
-// Build configuration
-plugins {
- `kotlin-library-conventions`
- id("org.kordamp.gradle.jandex") // Necessary for Quarkus to process annotations
-}
-
-dependencies {
- implementation(libs.jackson.annotations)
- implementation(libs.jakarta.validation)
- implementation(libs.microprofile.openapi.api)
-}
-
-tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
- kotlinOptions.javaParameters = true
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/JobState.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/JobState.kt
deleted file mode 100644
index a8e67ec5..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/JobState.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * State of a scenario for the simulator runner.
- */
-public enum class JobState {
- /**
- * The job is pending to be claimed by a runner.
- */
- PENDING,
-
- /**
- * The job is claimed by a runner.
- */
- CLAIMED,
-
- /**
- * The job is currently running.
- */
- RUNNING,
-
- /**
- * The job has finished.
- */
- FINISHED,
-
- /**
- * The job has failed.
- */
- FAILED,
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Machine.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Machine.kt
deleted file mode 100644
index 72163f51..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Machine.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-import com.fasterxml.jackson.annotation.JsonProperty
-
-/**
- * A machine in a rack.
- */
-public data class Machine(
- val id: String,
- val position: Int,
- val cpus: List<ProcessingUnit> = emptyList(),
- val gpus: List<ProcessingUnit> = emptyList(),
- @JsonProperty("memories")
- val memory: List<MemoryUnit> = emptyList(),
- @JsonProperty("storages")
- val storage: List<MemoryUnit> = emptyList(),
- val rackId: String? = null,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/MemoryUnit.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/MemoryUnit.kt
deleted file mode 100644
index 00560ad6..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/MemoryUnit.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * A memory unit in a system.
- */
-public data class MemoryUnit(
- val id: String,
- val name: String,
- val speedMbPerS: Double,
- val sizeMb: Double,
- val energyConsumptionW: Double,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/OperationalPhenomena.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/OperationalPhenomena.kt
deleted file mode 100644
index 28006d27..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/OperationalPhenomena.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * Object describing the enabled operational phenomena for a scenario.
- */
-public data class OperationalPhenomena(
- val failures: Boolean,
- val interference: Boolean,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProcessingUnit.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProcessingUnit.kt
deleted file mode 100644
index 86f40516..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProcessingUnit.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * A CPU model.
- */
-public data class ProcessingUnit(
- val id: String,
- val name: String,
- val clockRateMhz: Double,
- val numberOfCores: Int,
- val energyConsumptionW: Double,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProtocolError.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProtocolError.kt
deleted file mode 100644
index e7fe2702..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/ProtocolError.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * Container for reporting errors.
- */
-public data class ProtocolError(val code: Int, val message: String)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Rack.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Rack.kt
deleted file mode 100644
index c997e814..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Rack.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * A rack in a datacenter.
- */
-public data class Rack(
- val id: String,
- val name: String,
- val capacity: Int,
- val powerCapacityW: Double,
- val machines: List<Machine>,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Room.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Room.kt
deleted file mode 100644
index 5b305168..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Room.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * A room in a datacenter.
- */
-public data class Room(
- val id: String,
- val name: String,
- val tiles: Set<RoomTile>,
- val topologyId: String? = null,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/RoomTile.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/RoomTile.kt
deleted file mode 100644
index 666d66ee..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/RoomTile.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * A room tile.
- */
-public data class RoomTile(
- val id: String,
- val positionX: Double,
- val positionY: Double,
- val rack: Rack? = null,
- val roomId: String? = null,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Targets.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Targets.kt
deleted file mode 100644
index 25516ff0..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Targets.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-import jakarta.validation.constraints.Min
-
-/**
- * The targets of a portfolio.
- *
- * @param metrics The selected metrics to track during simulation.
- * @param repeats The number of repetitions per scenario.
- */
-public data class Targets(
- val metrics: Set<String>,
- @field:Min(1)
- val repeats: Int = 1,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Trace.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Trace.kt
deleted file mode 100644
index 2952a273..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Trace.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-/**
- * A workload trace available for simulation.
- *
- * @param id The unique identifier of the trace.
- * @param name The name of the trace.
- * @param type The type of trace.
- */
-public data class Trace(
- val id: String,
- val name: String,
- val type: String,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Workload.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Workload.kt
deleted file mode 100644
index 58daf817..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/Workload.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto
-
-import jakarta.validation.constraints.DecimalMax
-import jakarta.validation.constraints.DecimalMin
-
-/**
- * The workload to simulate for a scenario.
- */
-public data class Workload(val trace: Trace, val samplingFraction: Double) {
- /**
- * Specification for a workload.
- *
- * @param trace The unique identifier of the trace.
- * @param samplingFraction The fraction of the workload to sample.
- */
- public data class Spec(
- val trace: String,
- @DecimalMin(value = "0.001", message = "Sampling fraction must be non-zero")
- @DecimalMax(value = "1", message = "Sampling fraction cannot exceed one")
- val samplingFraction: Double,
- )
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Job.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Job.kt
deleted file mode 100644
index 34642436..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Job.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.runner
-
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import org.opendc.web.proto.JobState
-import java.time.Instant
-
-/**
- * A simulation job to be simulated by a runner.
- */
-@Schema(name = "Runner.Job")
-public data class Job(
- val id: Long,
- val scenario: Scenario,
- val state: JobState,
- val createdAt: Instant,
- val updatedAt: Instant,
- val runtime: Int,
- val results: Map<String, Any>? = null,
-) {
- /**
- * A request to update the state of a job.
- *
- * @property state The next state of the job.
- * @property runtime The runtime of the job (in seconds).
- * @property results The results of the job.
- */
- @Schema(name = "Runner.Job.Update")
- public data class Update(val state: JobState, val runtime: Int, val results: Map<String, Any>? = null)
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Portfolio.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Portfolio.kt
deleted file mode 100644
index 916d8cf0..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Portfolio.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.runner
-
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import org.opendc.web.proto.Targets
-import org.opendc.web.proto.user.Portfolio
-
-/**
- * A [Portfolio] as seen from the runner's perspective.
- *
- * @param id The unique identifier of the portfolio.
- * @param number The number of the portfolio for the project.
- * @param name The name of the portfolio.
- * @param targets The targets of the portfolio.
- */
-@Schema(name = "Runner.Portfolio")
-public data class Portfolio(
- val id: Long,
- val number: Int,
- val name: String,
- val targets: Targets,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Scenario.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Scenario.kt
deleted file mode 100644
index ebc10bb0..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Scenario.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.runner
-
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import org.opendc.web.proto.OperationalPhenomena
-import org.opendc.web.proto.Workload
-
-/**
- * A [Scenario] that is exposed to an OpenDC runner.
- */
-@Schema(name = "Runner.Scenario")
-public data class Scenario(
- val id: Long,
- val number: Int,
- val portfolio: Portfolio,
- val name: String,
- val workload: Workload,
- val topology: Topology,
- val phenomena: OperationalPhenomena,
- val schedulerName: String,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Topology.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Topology.kt
deleted file mode 100644
index 4bffdee9..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/runner/Topology.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.runner
-
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import org.opendc.web.proto.Room
-import java.time.Instant
-
-/**
- * A [Topology] that is exposed to an OpenDC runner.
- */
-@Schema(name = "Runner.Topology")
-public data class Topology(
- val id: Long,
- val number: Int,
- val name: String,
- val rooms: List<Room>,
- val createdAt: Instant,
- val updatedAt: Instant,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Job.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Job.kt
deleted file mode 100644
index dd2f209e..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Job.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-import org.opendc.web.proto.JobState
-import org.opendc.web.proto.runner.Job
-import java.time.Instant
-
-/**
- * A simulation job that is associated with a [Scenario].
- *
- * This entity is exposed in the runner-facing API via [Job].
- */
-public data class Job(
- val id: Long,
- val state: JobState,
- val createdAt: Instant,
- val updatedAt: Instant,
- val results: Map<String, Any>? = null,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Portfolio.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Portfolio.kt
deleted file mode 100644
index 6f433a04..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Portfolio.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-import jakarta.validation.constraints.NotBlank
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import org.opendc.web.proto.Targets
-
-/**
- * A portfolio is the composition of multiple scenarios.
- *
- * @param id The unique identifier of the portfolio.
- * @param number The number of the portfolio with respect to the project.
- * @param project The project to which the portfolio belongs.
- * @param name The name of the portfolio.
- * @param targets The targets of the portfolio.
- * @param scenarios The scenarios in the portfolio.
- */
-public data class Portfolio(
- val id: Long,
- val number: Int,
- val project: Project,
- val name: String,
- val targets: Targets,
- val scenarios: List<Scenario.Summary>,
-) {
- /**
- * A request to create a new portfolio.
- */
- @Schema(name = "Portfolio.Update")
- public data class Create(
- @field:NotBlank(message = "Name must not be empty")
- val name: String,
- val targets: Targets,
- )
-
- /**
- * A summary view of a [Portfolio] provided for nested relations.
- *
- * @param id The unique identifier of the portfolio.
- * @param number The number of the portfolio for the project.
- * @param name The name of the portfolio.
- * @param targets The targets of the portfolio.
- */
- @Schema(name = "Portfolio.Summary")
- public data class Summary(
- val id: Long,
- val number: Int,
- val name: String,
- val targets: Targets,
- )
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Project.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Project.kt
deleted file mode 100644
index 635552a9..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Project.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-import jakarta.validation.constraints.NotBlank
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import java.time.Instant
-
-/**
- * A project in OpenDC encapsulates all the datacenter designs and simulation runs for a set of users.
- */
-public data class Project(
- val id: Long,
- val name: String,
- val createdAt: Instant,
- val updatedAt: Instant,
- val role: ProjectRole,
-) {
- /**
- * A request to create a new project.
- */
- @Schema(name = "Project.Create")
- public data class Create(
- @field:NotBlank(message = "Name must not be empty") val name: String,
- )
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/ProjectRole.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/ProjectRole.kt
deleted file mode 100644
index 0f6de1fc..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/ProjectRole.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-/**
- * The role of a user in a project.
- */
-public enum class ProjectRole {
- /**
- * The user is allowed to view the project.
- */
- VIEWER,
-
- /**
- * The user is allowed to edit the project.
- */
- EDITOR,
-
- /**
- * The user owns the project (so he can delete it).
- */
- OWNER,
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Scenario.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Scenario.kt
deleted file mode 100644
index e0c790f5..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Scenario.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-import jakarta.validation.constraints.NotBlank
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import org.opendc.web.proto.OperationalPhenomena
-import org.opendc.web.proto.Workload
-
-/**
- * A single scenario to be explored by the simulator.
- */
-public data class Scenario(
- val id: Long,
- val number: Int,
- val project: Project,
- val portfolio: Portfolio.Summary,
- val name: String,
- val workload: Workload,
- val topology: Topology.Summary,
- val phenomena: OperationalPhenomena,
- val schedulerName: String,
- val jobs: List<Job>,
-) {
- /**
- * Create a new scenario.
- *
- * @param name The name of the scenario.
- * @param workload The workload specification to use for the scenario.
- * @param topology The number of the topology to use.
- * @param phenomena The phenomena to model during simulation.
- * @param schedulerName The name of the scheduler.
- */
- @Schema(name = "Scenario.Create")
- public data class Create(
- @field:NotBlank(message = "Name must not be empty")
- val name: String,
- val workload: Workload.Spec,
- val topology: Long,
- val phenomena: OperationalPhenomena,
- val schedulerName: String,
- )
-
- /**
- * A summary view of a [Scenario] provided for nested relations.
- *
- * @param id The unique identifier of the scenario.
- * @param number The number of the scenario for the project.
- * @param name The name of the scenario.
- * @param workload The workload to be modeled by the scenario.
- * @param phenomena The phenomena simulated for this scenario.
- * @param schedulerName The scheduler name to use for the experiment.
- * @param job The simulation job associated with the scenario.
- */
- @Schema(name = "Scenario.Summary")
- public data class Summary(
- val id: Long,
- val number: Int,
- val name: String,
- val workload: Workload,
- val topology: Topology.Summary,
- val phenomena: OperationalPhenomena,
- val schedulerName: String,
- val jobs: List<Job>,
- )
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Topology.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Topology.kt
deleted file mode 100644
index 0943eaf8..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/Topology.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-import jakarta.validation.constraints.NotBlank
-import org.eclipse.microprofile.openapi.annotations.media.Schema
-import org.opendc.web.proto.Room
-import java.time.Instant
-
-/**
- * Model for an OpenDC topology.
- */
-public data class Topology(
- val id: Long,
- val number: Int,
- val project: Project,
- val name: String,
- val rooms: List<Room>,
- val createdAt: Instant,
- val updatedAt: Instant,
-) {
- /**
- * Create a new topology for a project.
- */
- @Schema(name = "Topology.Create")
- public data class Create(
- @field:NotBlank(message = "Name must not be empty")
- val name: String,
- val rooms: List<Room>,
- )
-
- /**
- * Update an existing topology.
- */
- @Schema(name = "Topology.Update")
- public data class Update(val rooms: List<Room>)
-
- /**
- * A summary view of a [Topology] provided for nested relations.
- *
- * @param id The unique identifier of the topology.
- * @param number The number of the topology for the project.
- * @param name The name of the topology.
- * @param createdAt The instant at which the topology was created.
- * @param updatedAt The instant at which the topology was updated.
- */
- @Schema(name = "Topology.Summary")
- public data class Summary(
- val id: Long,
- val number: Int,
- val name: String,
- val createdAt: Instant,
- val updatedAt: Instant,
- )
-}
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/User.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/User.kt
deleted file mode 100644
index 33dad4ff..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/User.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-/**
- * A user of OpenDC.
- */
-public data class User(
- val userId: String,
- val accounting: UserAccounting,
-)
diff --git a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/UserAccounting.kt b/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/UserAccounting.kt
deleted file mode 100644
index 970721eb..00000000
--- a/opendc-web/opendc-web-proto/src/main/kotlin/org/opendc/web/proto/user/UserAccounting.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.proto.user
-
-import java.time.LocalDate
-
-/**
- * Accounting data for a user.
- */
-public data class UserAccounting(
- val periodEnd: LocalDate,
- val simulationTime: Int,
- val simulationTimeBudget: Int,
-)
diff --git a/opendc-web/opendc-web-runner-quarkus-deployment/build.gradle.kts b/opendc-web/opendc-web-runner-quarkus-deployment/build.gradle.kts
deleted file mode 100644
index 589337f4..00000000
--- a/opendc-web/opendc-web-runner-quarkus-deployment/build.gradle.kts
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Quarkus extension for the OpenDC experiment runner"
-
-// Build configuration
-plugins {
- `java-library-conventions`
-}
-
-dependencies {
- implementation(projects.opendcWeb.opendcWebRunnerQuarkus)
- implementation(projects.opendcTrace.opendcTraceApi)
-
- implementation(platform(libs.quarkus.bom))
- implementation(libs.quarkus.core.deployment)
- implementation(libs.quarkus.arc.deployment)
-}
diff --git a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerBuildItem.java b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerBuildItem.java
deleted file mode 100644
index 3be15ee3..00000000
--- a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerBuildItem.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner.deployment;
-
-import io.quarkus.builder.item.SimpleBuildItem;
-import io.quarkus.runtime.RuntimeValue;
-import org.opendc.web.runner.OpenDCRunner;
-
-/**
- * A {@link SimpleBuildItem} that produces an {@link OpenDCRunner} instance.
- */
-public final class OpenDCRunnerBuildItem extends SimpleBuildItem {
- private final RuntimeValue<OpenDCRunner> runner;
-
- public OpenDCRunnerBuildItem(RuntimeValue<OpenDCRunner> runner) {
- this.runner = runner;
- }
-
- public RuntimeValue<OpenDCRunner> getRunner() {
- return runner;
- }
-}
diff --git a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerConfig.java b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerConfig.java
deleted file mode 100644
index ccbc5e19..00000000
--- a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerConfig.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner.deployment;
-
-import io.quarkus.runtime.annotations.ConfigItem;
-import io.quarkus.runtime.annotations.ConfigRoot;
-
-/**
- * Build-time configuration for the OpenDC web runner extension.
- */
-@ConfigRoot(name = "opendc-runner")
-public class OpenDCRunnerConfig {
- /**
- * A flag to include the OpenDC web runner extension into the build.
- */
- @ConfigItem(defaultValue = "true")
- boolean include;
-}
diff --git a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerProcessor.java b/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerProcessor.java
deleted file mode 100644
index 85a973e7..00000000
--- a/opendc-web/opendc-web-runner-quarkus-deployment/src/main/java/org/opendc/web/runner/deployment/OpenDCRunnerProcessor.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner.deployment;
-
-import static io.quarkus.deployment.annotations.ExecutionTime.RUNTIME_INIT;
-
-import io.quarkus.arc.deployment.UnremovableBeanBuildItem;
-import io.quarkus.deployment.annotations.BuildProducer;
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.*;
-import io.quarkus.deployment.builditem.nativeimage.ServiceProviderBuildItem;
-import io.quarkus.deployment.util.ServiceUtil;
-import io.quarkus.runtime.RuntimeValue;
-import java.io.IOException;
-import java.util.Set;
-import java.util.function.BooleanSupplier;
-import org.opendc.trace.spi.TraceFormat;
-import org.opendc.web.runner.JobManager;
-import org.opendc.web.runner.OpenDCRunner;
-import org.opendc.web.runner.runtime.OpenDCRunnerRecorder;
-import org.opendc.web.runner.runtime.OpenDCRunnerRuntimeConfig;
-
-/**
- * Build processor for the OpenDC web runner Quarkus extension.
- */
-public class OpenDCRunnerProcessor {
-
- private static final String FEATURE = "opendc-runner";
-
- /**
- * Provide the {@link FeatureBuildItem} for this Quarkus extension.
- */
- @BuildStep(onlyIf = IsIncluded.class)
- public FeatureBuildItem feature() {
- return new FeatureBuildItem(FEATURE);
- }
-
- /**
- * Build step to register the trace formats used by OpenDC.
- */
- @BuildStep
- void registerTraceFormats(BuildProducer<ServiceProviderBuildItem> services) throws IOException {
- String service = "META-INF/services/" + TraceFormat.class.getName();
-
- Set<String> implementations =
- ServiceUtil.classNamesNamedIn(Thread.currentThread().getContextClassLoader(), service);
-
- services.produce(
- new ServiceProviderBuildItem(TraceFormat.class.getName(), implementations.toArray(new String[0])));
- }
-
- /**
- * Mark {@link JobManager} as unremoveable, since we look up this service dynamically in {@link OpenDCRunnerRecorder}.
- */
- @BuildStep
- UnremovableBeanBuildItem unremovableBeans() {
- return UnremovableBeanBuildItem.beanTypes(JobManager.class);
- }
-
- /**
- * Build step to create the runner service.
- */
- @BuildStep(onlyIf = IsIncluded.class)
- @Record(RUNTIME_INIT)
- ServiceStartBuildItem createRunnerService(
- OpenDCRunnerRecorder recorder,
- OpenDCRunnerRuntimeConfig config,
- BuildProducer<OpenDCRunnerBuildItem> runnerBuildItem) {
- RuntimeValue<OpenDCRunner> runner = recorder.createRunner(config);
- runnerBuildItem.produce(new OpenDCRunnerBuildItem(runner));
- return new ServiceStartBuildItem("OpenDCRunnerService");
- }
-
- /**
- * Build step to start the runner service.
- */
- @BuildStep(onlyIf = IsIncluded.class)
- @Record(RUNTIME_INIT)
- void startRunnerService(
- ApplicationStartBuildItem start,
- OpenDCRunnerBuildItem runnerBuildItem,
- OpenDCRunnerRecorder recorder,
- OpenDCRunnerRuntimeConfig config,
- ShutdownContextBuildItem shutdownContextBuildItem) {
- recorder.startRunner(runnerBuildItem.getRunner(), config, shutdownContextBuildItem);
- }
-
- /**
- * A {@link BooleanSupplier} to determine if the OpenDC web runner extension should be included.
- */
- private static class IsIncluded implements BooleanSupplier {
- OpenDCRunnerConfig config;
-
- @Override
- public boolean getAsBoolean() {
- return config.include;
- }
- }
-}
diff --git a/opendc-web/opendc-web-runner-quarkus/build.gradle.kts b/opendc-web/opendc-web-runner-quarkus/build.gradle.kts
deleted file mode 100644
index 8e4e08d5..00000000
--- a/opendc-web/opendc-web-runner-quarkus/build.gradle.kts
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Quarkus extension for the OpenDC experiment runner"
-
-plugins {
- `java-library-conventions`
- id("io.quarkus.extension")
-}
-
-quarkusExtension {
- deploymentModule.set("opendc-web-runner-quarkus-deployment")
-}
-
-dependencies {
- modules {
- module("javax.annotation:javax.annotation-api") {
- replacedBy("jakarta.annotation:jakarta.annotation-api", "javax has been replaced by Jakarta")
- }
- }
-
- api(projects.opendcWeb.opendcWebRunner)
-
- implementation(platform(libs.quarkus.bom))
- implementation(libs.quarkus.core.runtime)
-}
-
-evaluationDependsOn(projects.opendcWeb.opendcWebRunnerQuarkusDeployment.dependencyProject.path)
diff --git a/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRecorder.java b/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRecorder.java
deleted file mode 100644
index d5d524f1..00000000
--- a/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRecorder.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner.runtime;
-
-import io.quarkus.runtime.RuntimeValue;
-import io.quarkus.runtime.ShutdownContext;
-import io.quarkus.runtime.annotations.Recorder;
-import jakarta.enterprise.inject.spi.CDI;
-import java.io.File;
-import org.jboss.logging.Logger;
-import org.opendc.web.runner.JobManager;
-import org.opendc.web.runner.OpenDCRunner;
-
-/**
- * Helper class for starting the OpenDC web runner.
- */
-@Recorder
-public class OpenDCRunnerRecorder {
- private static final Logger LOGGER = Logger.getLogger(OpenDCRunnerRecorder.class.getName());
-
- /**
- * Helper method to create an {@link OpenDCRunner} instance.
- */
- public RuntimeValue<OpenDCRunner> createRunner(OpenDCRunnerRuntimeConfig config) {
- int parallelism = config.parallelism;
- if (parallelism < 0) {
- throw new IllegalArgumentException("Parallelism must be non-negative");
- } else if (parallelism == 0) {
- parallelism = Math.min(1, Runtime.getRuntime().availableProcessors() - 1);
- }
-
- JobManager manager = CDI.current().select(JobManager.class).get();
- OpenDCRunner runner = new OpenDCRunner(
- manager,
- new File(config.tracePath),
- parallelism,
- config.jobTimeout,
- config.pollInterval,
- config.heartbeatInterval);
-
- return new RuntimeValue<>(runner);
- }
-
- /**
- * Helper method to start the OpenDC runner service.
- */
- public void startRunner(
- RuntimeValue<OpenDCRunner> runner, OpenDCRunnerRuntimeConfig config, ShutdownContext shutdownContext) {
- if (config.enable) {
- LOGGER.info("Starting OpenDC Runner in background (polling every " + config.pollInterval + ")");
-
- Thread thread = new Thread(runner.getValue());
- thread.setName("opendc-runner");
- thread.start();
-
- shutdownContext.addShutdownTask(thread::interrupt);
- }
- }
-}
diff --git a/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRuntimeConfig.java b/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRuntimeConfig.java
deleted file mode 100644
index 61c07e48..00000000
--- a/opendc-web/opendc-web-runner-quarkus/src/main/java/org/opendc/web/runner/runtime/OpenDCRunnerRuntimeConfig.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner.runtime;
-
-import io.quarkus.runtime.annotations.ConfigItem;
-import io.quarkus.runtime.annotations.ConfigPhase;
-import io.quarkus.runtime.annotations.ConfigRoot;
-import java.time.Duration;
-
-/**
- * Configuration for the OpenDC web runner.
- */
-@ConfigRoot(phase = ConfigPhase.RUN_TIME, name = "opendc-runner")
-public class OpenDCRunnerRuntimeConfig {
- /**
- * Flag to indicate whether the runner should be enabled.
- */
- @ConfigItem(defaultValue = "true")
- public boolean enable;
-
- /**
- * The path where the workload traces are located.
- */
- @ConfigItem(defaultValue = "traces")
- public String tracePath;
-
- /**
- * The number of concurrent simulations
- */
- @ConfigItem(defaultValue = "1")
- public int parallelism;
-
- /**
- * The maximum duration of a job.
- */
- @ConfigItem(defaultValue = "10m")
- public Duration jobTimeout;
-
- /**
- * The interval between successive polls to the API.
- */
- @ConfigItem(defaultValue = "30s")
- public Duration pollInterval;
-
- /**
- * The interval between successive heartbeats to the API.
- */
- @ConfigItem(defaultValue = "1m")
- public Duration heartbeatInterval;
-}
diff --git a/opendc-web/opendc-web-runner-quarkus/src/main/resources/META-INF/quarkus-extension.yaml b/opendc-web/opendc-web-runner-quarkus/src/main/resources/META-INF/quarkus-extension.yaml
deleted file mode 100644
index b93b467a..00000000
--- a/opendc-web/opendc-web-runner-quarkus/src/main/resources/META-INF/quarkus-extension.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-name: "OpenDC Web Runner"
-metadata:
- status: "preview"
- unlisted: true
diff --git a/opendc-web/opendc-web-runner/Dockerfile b/opendc-web/opendc-web-runner/Dockerfile
deleted file mode 100644
index 9ec184ee..00000000
--- a/opendc-web/opendc-web-runner/Dockerfile
+++ /dev/null
@@ -1,27 +0,0 @@
-FROM eclipse-temurin:21-jdk-jammy
-MAINTAINER OpenDC Maintainers <opendc@atlarge-research.com>
-
-# Obtain (cache) Gradle wrapper
-COPY gradlew /app/
-COPY gradle /app/gradle
-WORKDIR /app
-RUN ./gradlew --version
-
-# Build project
-COPY ./ /app/
-RUN ./gradlew --no-daemon :opendc-web:opendc-web-runner:installDist
-
-FROM eclipse-temurin:21-jdk-jammy
-COPY --from=0 /app/opendc-web/opendc-web-runner/build/install /opt/
-COPY --from=0 /app/opendc-experiments/opendc-experiments-base/src/test/resources/workloadTraces \
- /opt/opendc/traces
-WORKDIR /opt/opendc
-CMD bin/opendc-web-runner
-
-LABEL org.opencontainers.image.authors="OpenDC Maintainers <opendc@atlarge-research.com>"
-LABEL org.opencontainers.image.url="https://opendc.org"
-LABEL org.opencontainers.image.documentation="https://opendc.org"
-LABEL org.opencontainers.image.source="https://github.com/atlarge-research/opendc"
-LABEL org.opencontainers.image.title="OpenDC Web Runner UI"
-LABEL org.opencontainers.image.description="OpenDC Web Runner Docker Image"
-LABEL org.opencontainers.image.vendor="AtLarge Research"
diff --git a/opendc-web/opendc-web-runner/build.gradle.kts b/opendc-web/opendc-web-runner/build.gradle.kts
deleted file mode 100644
index 97328324..00000000
--- a/opendc-web/opendc-web-runner/build.gradle.kts
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Experiment runner for OpenDC"
-
-// Build configuration
-plugins {
- `kotlin-library-conventions`
- distribution
-}
-
-val cli: SourceSet by sourceSets.creating {
- compileClasspath += sourceSets["main"].output
- runtimeClasspath += sourceSets["main"].output
-}
-
-val cliImplementation: Configuration by configurations.getting {
- extendsFrom(configurations["implementation"])
-}
-val cliRuntimeOnly: Configuration by configurations.getting
-val cliRuntimeClasspath: Configuration by configurations.getting {
- extendsFrom(configurations["runtimeClasspath"])
-}
-
-val cliJar by tasks.creating(Jar::class) {
- from(cli.output)
-
- archiveBaseName.set("${project.name}-cli")
-}
-
-dependencies {
- api(projects.opendcWeb.opendcWebClient)
- implementation(projects.opendcSimulator.opendcSimulatorCore)
- implementation(projects.opendcTrace.opendcTraceApi)
-
- implementation(libs.kotlin.logging)
- implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-workload")))
- implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-carbon")))
- implementation(project(mapOf("path" to ":opendc-experiments:opendc-experiments-base")))
- implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-topology")))
- implementation(project(mapOf("path" to ":opendc-compute:opendc-compute-failure")))
-
- cliImplementation(libs.clikt)
-
- cliRuntimeOnly(libs.log4j.core)
- cliRuntimeOnly(libs.log4j.slf4j)
- cliRuntimeOnly(libs.sentry.log4j2)
-}
-
-val createCli by tasks.creating(CreateStartScripts::class) {
- dependsOn(cliJar)
-
- applicationName = "opendc-runner"
- mainClass.set("org.opendc.web.runner.cli.MainKt")
- classpath = cliJar.outputs.files + cliRuntimeClasspath
- outputDir = project.layout.buildDirectory.get().asFile.resolve("scripts")
-}
-
-distributions {
- main {
- contents {
- into("bin") {
- from(createCli)
- }
-
- into("lib") {
- from(cliJar)
- from(cliRuntimeClasspath) // Also includes main classpath
- }
- }
- }
-}
diff --git a/opendc-web/opendc-web-runner/src/cli/kotlin/org/opendc/web/runner/Main.kt b/opendc-web/opendc-web-runner/src/cli/kotlin/org/opendc/web/runner/Main.kt
deleted file mode 100644
index 5d35fd98..00000000
--- a/opendc-web/opendc-web-runner/src/cli/kotlin/org/opendc/web/runner/Main.kt
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner
-
-import com.github.ajalt.clikt.core.CliktCommand
-import com.github.ajalt.clikt.parameters.options.convert
-import com.github.ajalt.clikt.parameters.options.default
-import com.github.ajalt.clikt.parameters.options.defaultLazy
-import com.github.ajalt.clikt.parameters.options.option
-import com.github.ajalt.clikt.parameters.options.required
-import com.github.ajalt.clikt.parameters.types.file
-import com.github.ajalt.clikt.parameters.types.int
-import mu.KotlinLogging
-import org.opendc.web.client.auth.OpenIdAuthController
-import org.opendc.web.client.runner.OpenDCRunnerClient
-import java.io.File
-import java.net.URI
-
-private val logger = KotlinLogging.logger {}
-
-/**
- * Represents the CLI command for starting the OpenDC web runner.
- */
-class RunnerCli : CliktCommand(name = "opendc-runner") {
- /**
- * The URL to the OpenDC API.
- */
- private val apiUrl by option(
- "--api-url",
- help = "url to the OpenDC API",
- envvar = "OPENDC_API_URL",
- )
- .convert { URI(it) }
- .default(URI("https://api.opendc.org/v2"))
-
- /**
- * The auth domain to use.
- */
- private val authDomain by option(
- "--auth-domain",
- help = "auth domain of the OpenDC API",
- envvar = "AUTH0_DOMAIN",
- )
- .required()
-
- /**
- * The auth domain to use.
- */
- private val authAudience by option(
- "--auth-audience",
- help = "auth audience of the OpenDC API",
- envvar = "AUTH0_AUDIENCE",
- )
- .required()
-
- /**
- * The auth client ID to use.
- */
- private val authClientId by option(
- "--auth-id",
- help = "auth client id of the OpenDC API",
- envvar = "AUTH0_CLIENT_ID",
- )
- .required()
-
- /**
- * The auth client secret to use.
- */
- private val authClientSecret by option(
- "--auth-secret",
- help = "auth client secret of the OpenDC API",
- envvar = "AUTH0_CLIENT_SECRET",
- )
- .required()
-
- /**
- * The path to the traces directory.
- */
- private val tracePath by option(
- "--traces",
- help = "path to the directory containing the traces",
- envvar = "OPENDC_TRACES",
- )
- .file(canBeFile = false)
- .defaultLazy { File("traces/") }
-
- /**
- * The number of threads used for simulations..
- */
- private val parallelism by option(
- "--parallelism",
- help = "maximum number of threads for simulations",
- )
- .int()
- .default(Runtime.getRuntime().availableProcessors() - 1)
-
- override fun run() {
- logger.info { "Starting OpenDC web runner" }
-
- val client = OpenDCRunnerClient(baseUrl = apiUrl, OpenIdAuthController(authDomain, authClientId, authClientSecret, authAudience))
- val manager = JobManager(client)
- val runner = OpenDCRunner(manager, tracePath, parallelism = parallelism)
-
- logger.info { "Watching for queued scenarios" }
- runner.run()
- }
-}
-
-/**
- * Main entry point of the runner.
- */
-fun main(args: Array<String>): Unit = RunnerCli().main(args)
diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/JobManager.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/JobManager.kt
deleted file mode 100644
index a517f3b4..00000000
--- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/JobManager.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner
-
-import org.opendc.web.client.runner.OpenDCRunnerClient
-import org.opendc.web.proto.runner.Job
-import org.opendc.web.runner.internal.JobManagerImpl
-
-/**
- * Interface used by the [OpenDCRunner] to manage the available jobs to be processed.
- */
-public interface JobManager {
- /**
- * Find the next job that the simulator needs to process.
- */
- public fun findNext(): Job?
-
- /**
- * Claim the simulation job with the specified id.
- */
- public fun claim(id: Long): Boolean
-
- /**
- * Update the heartbeat of the specified job.
- *
- * @param id The identifier of the job.
- * @param runtime The total runtime of the job.
- * @return `true` if the job can continue, `false` if the job has been cancelled.
- */
- public fun heartbeat(
- id: Long,
- runtime: Int,
- ): Boolean
-
- /**
- * Mark the job as failed.
- */
- public fun fail(
- id: Long,
- runtime: Int,
- )
-
- /**
- * Persist the specified results for the specified job.
- */
- public fun finish(
- id: Long,
- runtime: Int,
- results: Map<String, Any>,
- )
-
- public companion object {
- /**
- * Create a [JobManager] given the specified [client].
- */
- @JvmStatic
- @JvmName("create")
- public operator fun invoke(client: OpenDCRunnerClient): JobManager {
- return JobManagerImpl(client)
- }
- }
-}
diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt
deleted file mode 100644
index 83583eab..00000000
--- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/OpenDCRunner.kt
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner
-
-import mu.KotlinLogging
-import org.opendc.compute.failure.prefab.FailurePrefab
-import org.opendc.compute.failure.prefab.createFailureModelPrefab
-import org.opendc.compute.simulator.provisioner.Provisioner
-import org.opendc.compute.simulator.provisioner.registerComputeMonitor
-import org.opendc.compute.simulator.provisioner.setupComputeService
-import org.opendc.compute.simulator.provisioner.setupHosts
-import org.opendc.compute.simulator.scheduler.createPrefabComputeScheduler
-import org.opendc.compute.simulator.service.ComputeService
-import org.opendc.compute.topology.specs.ClusterSpec
-import org.opendc.compute.topology.specs.HostSpec
-import org.opendc.compute.topology.specs.PowerSourceSpec
-import org.opendc.compute.workload.ComputeWorkloadLoader
-import org.opendc.experiments.base.runner.replay
-import org.opendc.simulator.compute.models.CpuModel
-import org.opendc.simulator.compute.models.MachineModel
-import org.opendc.simulator.compute.models.MemoryUnit
-import org.opendc.simulator.compute.power.PowerModels
-import org.opendc.simulator.kotlin.runSimulation
-import org.opendc.web.proto.runner.Job
-import org.opendc.web.proto.runner.Scenario
-import org.opendc.web.proto.runner.Topology
-import org.opendc.web.runner.internal.WebComputeMonitor
-import java.io.File
-import java.time.Duration
-import java.time.Instant
-import java.time.temporal.ChronoUnit
-import java.util.Random
-import java.util.concurrent.Executors
-import java.util.concurrent.ForkJoinPool
-import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory
-import java.util.concurrent.ForkJoinWorkerThread
-import java.util.concurrent.RecursiveAction
-import java.util.concurrent.RecursiveTask
-import java.util.concurrent.ScheduledExecutorService
-import java.util.concurrent.TimeUnit
-
-/**
- * Class to execute the pending jobs via the OpenDC web API.
- *
- * @param manager The underlying [JobManager] to manage the available jobs.
- * @param tracePath The directory where the traces are located.
- * @param jobTimeout The maximum duration of a simulation job.
- * @param pollInterval The interval to poll the API with.
- * @param heartbeatInterval The interval to send a heartbeat to the API server.
- */
-public class OpenDCRunner(
- private val manager: JobManager,
- private val tracePath: File,
- parallelism: Int = Runtime.getRuntime().availableProcessors(),
- private val jobTimeout: Duration = Duration.ofMinutes(10),
- private val pollInterval: Duration = Duration.ofSeconds(30),
- private val heartbeatInterval: Duration = Duration.ofMinutes(1),
-) : Runnable {
- /**
- * Logging instance for this runner.
- */
- private val logger = KotlinLogging.logger {}
-
- /**
- * Helper class to load the workloads.
- */
- private val workloadLoader = ComputeWorkloadLoader(tracePath)
-
- /**
- * The [ForkJoinPool] that is used to execute the simulation jobs.
- */
- private val pool =
- ForkJoinPool(parallelism, RunnerThreadFactory(Thread.currentThread().contextClassLoader), null, false)
-
- /**
- * A [ScheduledExecutorService] to manage the heartbeat of simulation jobs as well as tracking the deadline of
- * individual simulations.
- */
- private val scheduler = Executors.newSingleThreadScheduledExecutor()
-
- /**
- * Start the runner process.
- *
- * This method will block until interrupted and poll the OpenDC API for new jobs to execute.
- */
- override fun run() {
- try {
- while (true) {
- val job = manager.findNext()
- if (job == null) {
- Thread.sleep(pollInterval.toMillis())
- continue
- }
-
- val id = job.id
-
- logger.info { "Found queued job $id: attempting to claim" }
-
- if (!manager.claim(id)) {
- logger.info { "Failed to claim scenario" }
- continue
- }
-
- pool.submit(JobAction(job))
- }
- } catch (_: InterruptedException) {
- // Gracefully exit when the thread is interrupted
- } finally {
- workloadLoader.reset()
-
- pool.shutdown()
- scheduler.shutdown()
-
- pool.awaitTermination(5, TimeUnit.SECONDS)
- }
- }
-
- /**
- * A [RecursiveAction] that runs a simulation job (consisting of possible multiple simulations).
- *
- * @param job The job to simulate.
- */
- private inner class JobAction(private val job: Job) : RecursiveAction() {
- override fun compute() {
- val id = job.id
- val scenario = job.scenario
- val startTime = Instant.now()
- val currentThread = Thread.currentThread()
-
- val heartbeat =
- scheduler.scheduleWithFixedDelay(
- {
- if (!manager.heartbeat(id, startTime.secondsSince())) {
- currentThread.interrupt()
- }
- },
- 0,
- heartbeatInterval.toMillis(),
- TimeUnit.MILLISECONDS,
- )
-
- try {
- val topology = convertTopology(scenario.topology)
- val jobs =
- (0 until scenario.portfolio.targets.repeats).map { repeat ->
- SimulationTask(
- scenario,
- repeat,
- topology,
- )
- }
- val results = invokeAll(jobs).map { it.rawResult }
-
- heartbeat.cancel(true)
-
- val duration = startTime.secondsSince()
- logger.info { "Finished simulation for job $id (in $duration seconds)" }
-
- manager.finish(
- id,
- duration,
- mapOf(
- "total_requested_burst" to results.map { it.totalActiveTime + it.totalIdleTime },
- "total_granted_burst" to results.map { it.totalActiveTime },
- "total_overcommitted_burst" to results.map { it.totalStealTime },
- "total_interfered_burst" to results.map { it.totalLostTime },
- "mean_cpu_usage" to results.map { it.meanCpuUsage },
- "mean_cpu_demand" to results.map { it.meanCpuDemand },
- "mean_num_deployed_images" to results.map { it.meanNumDeployedImages },
- "max_num_deployed_images" to results.map { it.maxNumDeployedImages },
- "total_power_draw" to results.map { it.totalPowerDraw },
- "total_failure_slices" to results.map { it.totalFailureSlices },
- "total_failure_vm_slices" to results.map { it.totalFailureVmSlices },
- "total_vms_submitted" to results.map { it.totalVmsSubmitted },
- "total_vms_queued" to results.map { it.totalVmsQueued },
- "total_vms_finished" to results.map { it.totalVmsFinished },
- "total_vms_failed" to results.map { it.totalVmsFailed },
- ),
- )
- } catch (e: Exception) {
- // Check whether the job failed due to exceeding its time budget
- if (Thread.interrupted()) {
- logger.info { "Simulation job $id exceeded time limit (${startTime.secondsSince()} seconds)" }
- } else {
- logger.info(e) { "Simulation job $id failed" }
- }
-
- try {
- heartbeat.cancel(true)
- manager.fail(id, startTime.secondsSince())
- } catch (e: Throwable) {
- logger.error(e) { "Failed to update job" }
- }
- }
- }
-
- /**
- * Calculate the seconds since the specified instant.
- */
- private fun Instant.secondsSince(): Int {
- return ChronoUnit.SECONDS.between(this, Instant.now()).toInt()
- }
- }
-
- /**
- * A [RecursiveTask] that simulates a single scenario.
- *
- * @param scenario The scenario to simulate.
- * @param repeat The repeat number used to seed the simulation.
- * @param topologyHosts The topology to simulate.
- */
- private inner class SimulationTask(
- private val scenario: Scenario,
- private val repeat: Int,
- private val topologyHosts: List<HostSpec>,
- ) : RecursiveTask<WebComputeMonitor.Results>() {
- override fun compute(): WebComputeMonitor.Results {
- val monitor = WebComputeMonitor()
-
- // Schedule task that interrupts the simulation if it runs for too long.
- val currentThread = Thread.currentThread()
- val interruptTask =
- scheduler.schedule({ currentThread.interrupt() }, jobTimeout.toMillis(), TimeUnit.MILLISECONDS)
-
- try {
- runSimulation(monitor)
- } finally {
- interruptTask.cancel(false)
- }
-
- return monitor.collectResults()
- }
-
- /**
- * Run a single simulation of the scenario.
- */
- private fun runSimulation(monitor: WebComputeMonitor) =
- runSimulation {
- val serviceDomain = "compute.opendc.org"
- val seed = repeat.toLong()
-
- val scenario = scenario
-
- val powerSourceSpec =
- PowerSourceSpec(
- totalPower = Long.MAX_VALUE,
- )
- val topology = listOf(ClusterSpec("cluster", topologyHosts, powerSourceSpec))
-
- Provisioner(dispatcher, seed).use { provisioner ->
-
-// val workload =
-// trace(scenario.workload.trace.id).sampleByLoad(scenario.workload.samplingFraction)
-// val vms = workload.resolve(workloadLoader, Random(seed))
-
- val vms = workloadLoader.sampleByLoad(scenario.workload.samplingFraction)
- val startTime = vms.minOf { it.submittedAt }
-
- provisioner.runSteps(
- setupComputeService(
- serviceDomain,
- { createPrefabComputeScheduler(scenario.schedulerName, Random(it.seeder.nextLong()), timeSource) },
- ),
- registerComputeMonitor(serviceDomain, monitor),
- setupHosts(serviceDomain, topology, startTime),
- )
-
- val service = provisioner.registry.resolve(serviceDomain, ComputeService::class.java)!!
-
- val phenomena = scenario.phenomena
- val failureModel =
- if (phenomena.failures) {
- createFailureModelPrefab(coroutineContext, timeSource, service, Random(seed), FailurePrefab.G5k06Exp)
- } else {
- null
- }
-
- // Run workload trace
- service.replay(timeSource, vms, seed = seed)
-
- val serviceMetrics = service.getSchedulerStats()
- logger.debug {
- "Scheduler " +
- "Success=${serviceMetrics.attemptsSuccess} " +
- "Failure=${serviceMetrics.attemptsFailure} " +
- "Pending=${serviceMetrics.tasksPending} " +
- "Active=${serviceMetrics.tasksActive}"
- }
- }
- }
- }
-
- /**
- * Convert the specified [topology] into an [Topology] understood by OpenDC.
- */
- private fun convertTopology(topology: Topology): List<HostSpec> {
- val res = mutableListOf<HostSpec>()
- val random = Random(0)
-
- val machines =
- topology.rooms.asSequence()
- .flatMap { room ->
- room.tiles.flatMap { tile ->
- val rack = tile.rack
- rack?.machines?.map { machine -> rack to machine } ?: emptyList()
- }
- }
-
- for ((rack, machine) in machines) {
- val clusterId = rack.id
- val position = machine.position
-
- val processors =
- machine.cpus.map { cpu ->
- CpuModel(
- 0,
- cpu.numberOfCores,
- cpu.clockRateMhz,
- "Intel",
- "amd64",
- cpu.name,
- )
- }
-
- val memoryUnits =
- machine.memory.map { memory ->
- MemoryUnit(
- "Samsung",
- memory.name,
- memory.speedMbPerS,
- memory.sizeMb.toLong(),
- )
- }
-
- val energyConsumptionW = machine.cpus.sumOf { it.energyConsumptionW }
- val cpuPowerModel = PowerModels.linear(2 * energyConsumptionW, energyConsumptionW * 0.5)
-
- val spec =
- HostSpec(
- "node-$clusterId-$position",
- "node-$clusterId",
- clusterId,
- MachineModel(processors, memoryUnits[0]),
- cpuPowerModel,
- null,
- )
-
- res += spec
- }
-
- return res
- }
-
- /**
- * A custom [ForkJoinWorkerThreadFactory] that uses the [ClassLoader] of specified by the runner.
- */
- private class RunnerThreadFactory(private val classLoader: ClassLoader) : ForkJoinWorkerThreadFactory {
- override fun newThread(pool: ForkJoinPool): ForkJoinWorkerThread =
- object : ForkJoinWorkerThread(pool) {
- init {
- contextClassLoader = classLoader
- }
- }
- }
-}
diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/JobManagerImpl.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/JobManagerImpl.kt
deleted file mode 100644
index 7081041c..00000000
--- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/JobManagerImpl.kt
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner.internal
-
-import org.opendc.web.client.runner.OpenDCRunnerClient
-import org.opendc.web.proto.JobState
-import org.opendc.web.proto.runner.Job
-import org.opendc.web.runner.JobManager
-
-/**
- * Default implementation of [JobManager] that uses the OpenDC client to receive jobs.
- */
-internal class JobManagerImpl(private val client: OpenDCRunnerClient) : JobManager {
- override fun findNext(): Job? {
- return client.jobs.queryPending().firstOrNull()
- }
-
- override fun claim(id: Long): Boolean {
- return try {
- client.jobs.update(id, Job.Update(JobState.CLAIMED, 0))
- true
- } catch (e: IllegalStateException) {
- false
- }
- }
-
- override fun heartbeat(
- id: Long,
- runtime: Int,
- ): Boolean {
- val res = client.jobs.update(id, Job.Update(JobState.RUNNING, runtime))
- return res?.state != JobState.FAILED
- }
-
- override fun fail(
- id: Long,
- runtime: Int,
- ) {
- client.jobs.update(id, Job.Update(JobState.FAILED, runtime))
- }
-
- override fun finish(
- id: Long,
- runtime: Int,
- results: Map<String, Any>,
- ) {
- client.jobs.update(id, Job.Update(JobState.FINISHED, runtime))
- }
-}
diff --git a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/WebComputeMonitor.kt b/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/WebComputeMonitor.kt
deleted file mode 100644
index 9288b403..00000000
--- a/opendc-web/opendc-web-runner/src/main/kotlin/org/opendc/web/runner/internal/WebComputeMonitor.kt
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.runner.internal
-
-import org.opendc.compute.simulator.telemetry.ComputeMonitor
-import org.opendc.compute.simulator.telemetry.table.host.HostTableReader
-import org.opendc.compute.simulator.telemetry.table.service.ServiceData
-import org.opendc.compute.simulator.telemetry.table.service.ServiceTableReader
-import org.opendc.compute.simulator.telemetry.table.service.toServiceData
-import kotlin.math.roundToLong
-
-/**
- * A [ComputeMonitor] that tracks the aggregate metrics for each repeat.
- */
-internal class WebComputeMonitor : ComputeMonitor {
- override fun record(reader: HostTableReader) {
- val slices = reader.downtime / sliceLength
-
- hostAggregateMetrics =
- AggregateHostMetrics(
- hostAggregateMetrics.totalActiveTime + reader.cpuActiveTime,
- hostAggregateMetrics.totalIdleTime + reader.cpuIdleTime,
- hostAggregateMetrics.totalStealTime + reader.cpuStealTime,
- hostAggregateMetrics.totalLostTime + reader.cpuLostTime,
- hostAggregateMetrics.totalPowerDraw + reader.energyUsage,
- hostAggregateMetrics.totalFailureSlices + slices,
- hostAggregateMetrics.totalFailureVmSlices + reader.tasksActive * slices,
- )
-
- hostMetrics.compute(reader.hostInfo.name) { _, prev ->
- HostMetrics(
- reader.cpuUsage + (prev?.cpuUsage ?: 0.0),
- reader.cpuDemand + (prev?.cpuDemand ?: 0.0),
- reader.tasksActive + (prev?.instanceCount ?: 0),
- 1 + (prev?.count ?: 0),
- )
- }
- }
-
- private var hostAggregateMetrics: AggregateHostMetrics = AggregateHostMetrics()
- private val hostMetrics: MutableMap<String, HostMetrics> = mutableMapOf()
- private val sliceLength: Long = 5 * 60L
-
- private data class AggregateHostMetrics(
- val totalActiveTime: Long = 0L,
- val totalIdleTime: Long = 0L,
- val totalStealTime: Long = 0L,
- val totalLostTime: Long = 0L,
- val totalPowerDraw: Double = 0.0,
- val totalFailureSlices: Double = 0.0,
- val totalFailureVmSlices: Double = 0.0,
- )
-
- private data class HostMetrics(
- val cpuUsage: Double,
- val cpuDemand: Double,
- val instanceCount: Long,
- val count: Long,
- )
-
- private lateinit var serviceData: ServiceData
-
- override fun record(reader: ServiceTableReader) {
- serviceData = reader.toServiceData()
- }
-
- /**
- * Collect the results of the simulation.
- */
- fun collectResults(): Results {
- val hostAggregateMetrics = hostAggregateMetrics
- val hostMetrics = hostMetrics
- val serviceData = serviceData
-
- return Results(
- hostAggregateMetrics.totalActiveTime,
- hostAggregateMetrics.totalIdleTime,
- hostAggregateMetrics.totalStealTime,
- hostAggregateMetrics.totalLostTime,
- hostMetrics.map { it.value.cpuUsage / it.value.count }.average().let { if (it.isNaN()) 0.0 else it },
- hostMetrics.map { it.value.cpuDemand / it.value.count }.average().let { if (it.isNaN()) 0.0 else it },
- hostMetrics.map { it.value.instanceCount.toDouble() / it.value.count }.average().let { if (it.isNaN()) 0.0 else it },
- hostMetrics.map { it.value.instanceCount.toDouble() / it.value.count }.maxOrNull() ?: 0.0,
- hostAggregateMetrics.totalPowerDraw,
- hostAggregateMetrics.totalFailureSlices.roundToLong(),
- hostAggregateMetrics.totalFailureVmSlices.roundToLong(),
- serviceData.tasksTotal,
- serviceData.tasksPending,
- serviceData.tasksTotal - serviceData.tasksPending - serviceData.tasksActive,
- serviceData.attemptsTerminated,
- )
- }
-
- /**
- * Structure of the results of a single simulation.
- */
- data class Results(
- val totalActiveTime: Long,
- val totalIdleTime: Long,
- val totalStealTime: Long,
- val totalLostTime: Long,
- val meanCpuUsage: Double,
- val meanCpuDemand: Double,
- val meanNumDeployedImages: Double,
- val maxNumDeployedImages: Double,
- val totalPowerDraw: Double,
- val totalFailureSlices: Long,
- val totalFailureVmSlices: Long,
- val totalVmsSubmitted: Int,
- val totalVmsQueued: Int,
- val totalVmsFinished: Int,
- val totalVmsFailed: Int,
- )
-}
diff --git a/opendc-web/opendc-web-runner/src/main/resources/log4j2.xml b/opendc-web/opendc-web-runner/src/main/resources/log4j2.xml
deleted file mode 100644
index ad99cc00..00000000
--- a/opendc-web/opendc-web-runner/src/main/resources/log4j2.xml
+++ /dev/null
@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- ~ MIT License
- ~
- ~ Copyright (c) 2020 atlarge-research
- ~
- ~ Permission is hereby granted, free of charge, to any person obtaining a copy
- ~ of this software and associated documentation files (the "Software"), to deal
- ~ in the Software without restriction, including without limitation the rights
- ~ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- ~ copies of the Software, and to permit persons to whom the Software is
- ~ furnished to do so, subject to the following conditions:
- ~
- ~ The above copyright notice and this permission notice shall be included in all
- ~ copies or substantial portions of the Software.
- ~
- ~ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- ~ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- ~ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- ~ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- ~ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- ~ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- ~ SOFTWARE.
- -->
-
-<Configuration status="WARN" packages="org.apache.logging.log4j.core,io.sentry.log4j2">
- <Appenders>
- <Console name="Console" target="SYSTEM_OUT">
- <PatternLayout pattern="%d{HH:mm:ss.SSS} [%highlight{%-5level}] %logger{36} - %msg%n" disableAnsi="false"/>
- </Console>
-
- <Sentry name="Sentry" />
- </Appenders>
- <Loggers>
- <Logger name="org.opendc" level="warn" additivity="false">
- <AppenderRef ref="Console"/>
- <AppenderRef ref="Sentry"/>
- </Logger>
- <Logger name="org.opendc.web.runner" level="info" additivity="false">
- <AppenderRef ref="Console"/>
- <AppenderRef ref="Sentry"/>
- </Logger>
- <Root level="info">
- <AppenderRef level="error" ref="Console"/>
- <AppenderRef ref="Sentry"/>
- </Root>
- </Loggers>
-</Configuration>
diff --git a/opendc-web/opendc-web-server/Dockerfile b/opendc-web/opendc-web-server/Dockerfile
deleted file mode 100644
index 2aee7ddf..00000000
--- a/opendc-web/opendc-web-server/Dockerfile
+++ /dev/null
@@ -1,33 +0,0 @@
-FROM eclipse-temurin:21-jdk-jammy
-MAINTAINER OpenDC Maintainers <opendc@atlarge-research.com>
-
-# Obtain (cache) Gradle wrapper
-COPY gradlew /app/
-COPY gradle /app/gradle
-WORKDIR /app
-RUN ./gradlew --version
-
-# Build project
-ARG OPENDC_AUTH0_DOMAIN
-ARG OPENDC_AUTH0_AUDIENCE
-ARG OPENDC_AUTH0_DOCS_CLIENT_ID
-
-ENV OPENDC_AUTH0_DOMAIN=$OPENDC_AUTH0_DOMAIN
-ENV OPENDC_AUTH0_AUDIENCE=$OPENDC_AUTH0_AUDIENCE
-ENV OPENDC_AUTH0_DOCS_CLIENT_ID=$OPENDC_AUTH0_DOCS_CLIENT_ID
-
-COPY ./ /app/
-RUN ./gradlew --no-daemon :opendc-web:opendc-web-server:quarkusBuild -Dquarkus.profile=docker
-
-FROM eclipse-temurin:21-jdk-jammy
-COPY --from=0 /app/opendc-web/opendc-web-server/build/quarkus-app /opt/opendc
-WORKDIR /opt/opendc
-CMD java -jar quarkus-run.jar
-
-LABEL org.opencontainers.image.authors="OpenDC Maintainers <opendc@atlarge-research.com>"
-LABEL org.opencontainers.image.url="https://opendc.org"
-LABEL org.opencontainers.image.documentation="https://opendc.org"
-LABEL org.opencontainers.image.source="https://github.com/atlarge-research/opendc"
-LABEL org.opencontainers.image.title="OpenDC"
-LABEL org.opencontainers.image.description="OpenDC Docker Image"
-LABEL org.opencontainers.image.vendor="AtLarge Research"
diff --git a/opendc-web/opendc-web-server/build.gradle.kts b/opendc-web/opendc-web-server/build.gradle.kts
deleted file mode 100644
index 484e98c0..00000000
--- a/opendc-web/opendc-web-server/build.gradle.kts
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Web server of OpenDC"
-
-// Build configuration
-plugins {
- `quarkus-conventions`
- distribution
-}
-
-dependencies {
- implementation(enforcedPlatform(libs.quarkus.bom))
-
- implementation(projects.opendcWeb.opendcWebProto)
- testImplementation("junit:junit:4.13.1")
- testImplementation("junit:junit:4.13.1")
- compileOnly(projects.opendcWeb.opendcWebUiQuarkusDeployment) // Temporary fix for Quarkus/Gradle issues
- compileOnly(projects.opendcWeb.opendcWebRunnerQuarkusDeployment)
- implementation(projects.opendcWeb.opendcWebUiQuarkus)
- implementation(projects.opendcWeb.opendcWebRunnerQuarkus)
-
- implementation(libs.quarkus.kotlin)
- implementation(libs.quarkus.resteasy.core)
- implementation(libs.quarkus.resteasy.jackson)
- implementation(libs.jackson.module.kotlin)
- implementation(libs.quarkus.smallrye.openapi)
-
- implementation(libs.quarkus.security)
- implementation(libs.quarkus.oidc)
-
- implementation(libs.quarkus.hibernate.orm.core)
- implementation(libs.quarkus.hibernate.orm.panache)
- implementation(libs.quarkus.hibernate.validator)
- implementation(libs.quarkus.flyway)
- implementation(libs.quarkus.jdbc.postgresql)
- implementation(libs.quarkus.jdbc.h2)
- implementation(libs.hypersistence.utils.hibernate)
-
- testImplementation(libs.quarkus.junit5.core)
- testImplementation(libs.quarkus.jacoco)
- testImplementation(libs.quarkus.panache.mock)
- testImplementation(libs.restassured.core)
- testImplementation(libs.quarkus.test.security)
- testImplementation(libs.quarkus.jdbc.h2)
-}
-
-val createStartScripts by tasks.creating(CreateStartScripts::class) {
- applicationName = "opendc-server"
- mainClass.set("io.quarkus.bootstrap.runner.QuarkusEntryPoint")
- classpath = files("lib/quarkus-run.jar")
- outputDir = project.layout.buildDirectory.get().asFile.resolve("scripts")
-}
-
-distributions {
- main {
- distributionBaseName.set("opendc")
-
- contents {
- from("../../LICENSE.txt")
- from("config") {
- into("config")
- }
-
- from(createStartScripts) {
- into("bin")
- }
- from(tasks.quarkusBuild) {
- into("lib")
- }
-
- from("../../traces") {
- into("traces")
- }
- }
- }
-}
diff --git a/opendc-web/opendc-web-server/config/application.properties b/opendc-web/opendc-web-server/config/application.properties
deleted file mode 100644
index 30eaaef9..00000000
--- a/opendc-web/opendc-web-server/config/application.properties
+++ /dev/null
@@ -1 +0,0 @@
-# Custom server properties
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java
deleted file mode 100644
index a0ac390f..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Job.java
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.Panache;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.*;
-import java.time.Instant;
-import java.util.Map;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.JobState;
-
-/**
- * A simulation job to be run by the simulator.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "Job.updateOne",
- query =
- """
- UPDATE Job j
- SET j.state = :newState, j.updatedAt = :updatedAt, j.runtime = :runtime, j.results = :results
- WHERE j.id = :id AND j.state = :oldState
- """)
-})
-public class Job extends PanacheEntityBase {
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "jobSeq", sequenceName = "job_id_seq", allocationSize = 1, initialValue = 3)
- @GeneratedValue(generator = "jobSeq")
- public Long id;
-
- @ManyToOne(optional = false, fetch = FetchType.EAGER)
- @JoinColumn(name = "scenario_id", foreignKey = @ForeignKey(name = "fk_jobs_scenario"), nullable = false)
- public Scenario scenario;
-
- @Column(name = "created_by", nullable = false, updatable = false)
- public String createdBy;
-
- @Column(name = "created_at", nullable = false, updatable = false)
- public Instant createdAt;
-
- /**
- * The number of simulation runs to perform.
- */
- @Column(nullable = false, updatable = false)
- public int repeats;
-
- /**
- * The instant at which the job was updated.
- */
- @Column(name = "updated_at", nullable = false)
- public Instant updatedAt;
-
- /**
- * The state of the job.
- */
- @Enumerated(EnumType.STRING)
- @Column(nullable = false)
- public JobState state = JobState.PENDING;
-
- /**
- * The runtime of the job (in seconds).
- */
- @Column(nullable = false)
- public int runtime = 0;
-
- /**
- * Experiment results in JSON
- */
- @Column(columnDefinition = "jsonb")
- @Type(JsonType.class)
- public Map<String, ?> results = null;
-
- /**
- * Construct a {@link Job} instance.
- */
- public Job(Scenario scenario, String createdBy, Instant createdAt, int repeats) {
- this.createdBy = createdBy;
- this.scenario = scenario;
- this.createdAt = createdAt;
- this.updatedAt = createdAt;
- this.repeats = repeats;
- }
-
- /**
- * JPA constructor
- */
- protected Job() {}
-
- /**
- * Find {@link Job}s in the specified {@link JobState}.
- *
- * @param state The state of the jobs to find.
- * @return A query for jobs that are in the specified state.
- */
- public static PanacheQuery<Job> findByState(JobState state) {
- return find("state", state);
- }
-
- /**
- * Atomically update this job.
- *
- * @param newState The new state to enter into.
- * @param time The time at which the update occurs.
- * @param results The results to possible set.
- * @return <code>true</code> when the update succeeded`, <code>false</code> when there was a conflict.
- */
- public boolean updateAtomically(JobState newState, Instant time, int runtime, Map<String, ?> results) {
- long count = update(
- "#Job.updateOne",
- Parameters.with("id", id)
- .and("oldState", state)
- .and("newState", newState)
- .and("updatedAt", time)
- .and("runtime", runtime)
- .and("results", results));
- Panache.getEntityManager().refresh(this);
- return count > 0;
- }
-
- /**
- * Determine whether the job is allowed to transition to <code>newState</code>.
- *
- * @param newState The new state to transition to.
- * @return <code>true</code> if the transition to the new state is legal, <code>false</code> otherwise.
- */
- public boolean canTransitionTo(JobState newState) {
- // Note that we always allow transitions from the state
- return newState == this.state
- || switch (this.state) {
- case PENDING -> newState == JobState.CLAIMED;
- case CLAIMED -> newState == JobState.RUNNING || newState == JobState.FAILED;
- case RUNNING -> newState == JobState.FINISHED || newState == JobState.FAILED;
- case FINISHED, FAILED -> false;
- };
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java
deleted file mode 100644
index c2695192..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Portfolio.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.CascadeType;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.Id;
-import jakarta.persistence.Index;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.ManyToOne;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.OneToMany;
-import jakarta.persistence.OrderBy;
-import jakarta.persistence.SequenceGenerator;
-import jakarta.persistence.Table;
-import jakarta.persistence.UniqueConstraint;
-import java.util.HashSet;
-import java.util.Set;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.Targets;
-
-/**
- * A portfolio is the composition of multiple scenarios.
- */
-@Entity
-@Table(
- uniqueConstraints = {
- @UniqueConstraint(
- name = "uk_portfolios_number",
- columnNames = {"project_id", "number"})
- },
- indexes = {@Index(name = "ux_portfolios_number", columnList = "project_id, number")})
-@NamedQueries({
- @NamedQuery(name = "Portfolio.findByProject", query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId"),
- @NamedQuery(
- name = "Portfolio.findOneByProject",
- query = "SELECT p FROM Portfolio p WHERE p.project.id = :projectId AND p.number = :number")
-})
-public class Portfolio extends PanacheEntityBase {
-
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "portfolioSeq", sequenceName = "portfolio_id_seq", allocationSize = 1, initialValue = 4)
- @GeneratedValue(generator = "portfolioSeq")
- public Long id;
-
- /**
- * The {@link Project} this portfolio belongs to.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "project_id", nullable = false)
- public Project project;
-
- /**
- * Unique number of the portfolio for the project.
- */
- @Column(nullable = false)
- public int number;
-
- /**
- * The name of this portfolio.
- */
- @Column(nullable = false)
- public String name;
-
- /**
- * The portfolio targets (metrics, repetitions).
- */
- @Column(columnDefinition = "jsonb", nullable = false, updatable = false)
- @Type(JsonType.class)
- public Targets targets;
-
- /**
- * The scenarios in this portfolio.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "portfolio",
- orphanRemoval = true)
- @OrderBy("id ASC")
- public Set<Scenario> scenarios = new HashSet<>();
-
- /**
- * Construct a {@link Portfolio} object.
- */
- public Portfolio(Project project, int number, String name, Targets targets) {
- this.project = project;
- this.number = number;
- this.name = name;
- this.targets = targets;
- }
-
- /**
- * JPA constructor
- */
- protected Portfolio() {}
-
- /**
- * Find all {@link Portfolio}s that belong to the specified project
- *
- * @param projectId The unique identifier of the project.
- * @return The query of portfolios that belong to the specified project.
- */
- public static PanacheQuery<Portfolio> findByProject(long projectId) {
- return find("#Portfolio.findByProject", Parameters.with("projectId", projectId));
- }
-
- /**
- * Find the {@link Portfolio} with the specified <code>number</code> belonging to the specified project.
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the scenario.
- * @return The portfolio or <code>null</code> if it does not exist.
- */
- public static Portfolio findByProject(long projectId, int number) {
- return find(
- "#Portfolio.findOneByProject",
- Parameters.with("projectId", projectId).and("number", number))
- .firstResult();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java
deleted file mode 100644
index f4e5305d..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Project.java
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.Panache;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.CascadeType;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.Id;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.OneToMany;
-import jakarta.persistence.OrderBy;
-import jakarta.persistence.SequenceGenerator;
-import jakarta.persistence.Table;
-import java.time.Instant;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * A project in OpenDC encapsulates all the datacenter designs and simulation runs for a set of users.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "Project.findByUser",
- query =
- """
- SELECT a
- FROM ProjectAuthorization a
- WHERE a.key.userName = :userName
- """),
- @NamedQuery(
- name = "Project.allocatePortfolio",
- query =
- """
- UPDATE Project p
- SET p.portfoliosCreated = :oldState + 1, p.updatedAt = :now
- WHERE p.id = :id AND p.portfoliosCreated = :oldState
- """),
- @NamedQuery(
- name = "Project.allocateTopology",
- query =
- """
- UPDATE Project p
- SET p.topologiesCreated = :oldState + 1, p.updatedAt = :now
- WHERE p.id = :id AND p.topologiesCreated = :oldState
- """),
- @NamedQuery(
- name = "Project.allocateScenario",
- query =
- """
- UPDATE Project p
- SET p.scenariosCreated = :oldState + 1, p.updatedAt = :now
- WHERE p.id = :id AND p.scenariosCreated = :oldState
- """)
-})
-public class Project extends PanacheEntityBase {
-
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "projectSeq", sequenceName = "project_id_seq", allocationSize = 1, initialValue = 7)
- @GeneratedValue(generator = "projectSeq")
- public Long id;
-
- /**
- * The name of the project.
- */
- @Column(nullable = false)
- public String name;
-
- /**
- * The instant at which the project was created.
- */
- @Column(name = "created_at", nullable = false, updatable = false)
- public Instant createdAt;
-
- /**
- * The instant at which the project was updated.
- */
- @Column(name = "updated_at", nullable = false)
- public Instant updatedAt;
-
- /**
- * The portfolios belonging to this project.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "project",
- orphanRemoval = true)
- @OrderBy("id ASC")
- public Set<Portfolio> portfolios = new HashSet<>();
-
- /**
- * The number of portfolios created for this project (including deleted portfolios).
- */
- @Column(name = "portfolios_created", nullable = false)
- public int portfoliosCreated = 0;
-
- /**
- * The topologies belonging to this project.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "project",
- orphanRemoval = true)
- @OrderBy("id ASC")
- public Set<Topology> topologies = new HashSet<>();
-
- /**
- * The number of topologies created for this project (including deleted topologies).
- */
- @Column(name = "topologies_created", nullable = false)
- public int topologiesCreated = 0;
-
- /**
- * The scenarios belonging to this project.
- */
- @OneToMany(mappedBy = "project", orphanRemoval = true)
- public Set<Scenario> scenarios = new HashSet<>();
-
- /**
- * The number of scenarios created for this project (including deleted scenarios).
- */
- @Column(name = "scenarios_created", nullable = false)
- public int scenariosCreated = 0;
-
- /**
- * The users authorized to access the project.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "project",
- orphanRemoval = true)
- public Set<ProjectAuthorization> authorizations = new HashSet<>();
-
- /**
- * Construct a {@link Project} object.
- */
- public Project(String name, Instant createdAt) {
- this.name = name;
- this.createdAt = createdAt;
- this.updatedAt = createdAt;
- }
-
- /**
- * JPA constructor
- */
- protected Project() {}
-
- /**
- * Allocate the next portfolio number for the specified [project].
- *
- * @param time The time at which the new portfolio is created.
- */
- public int allocatePortfolio(Instant time) {
- for (int i = 0; i < 4; i++) {
- long count = update(
- "#Project.allocatePortfolio",
- Parameters.with("id", id).and("oldState", portfoliosCreated).and("now", time));
- if (count > 0) {
- return portfoliosCreated + 1;
- } else {
- Panache.getEntityManager().refresh(this);
- }
- }
-
- throw new IllegalStateException("Failed to allocate next portfolio");
- }
-
- /**
- * Allocate the next topology number for the specified [project].
- *
- * @param time The time at which the new topology is created.
- */
- public int allocateTopology(Instant time) {
- for (int i = 0; i < 4; i++) {
- long count = update(
- "#Project.allocateTopology",
- Parameters.with("id", id).and("oldState", topologiesCreated).and("now", time));
- if (count > 0) {
- return topologiesCreated + 1;
- } else {
- Panache.getEntityManager().refresh(this);
- }
- }
-
- throw new IllegalStateException("Failed to allocate next topology");
- }
-
- /**
- * Allocate the next scenario number for the specified [project].
- *
- * @param time The time at which the new scenario is created.
- */
- public int allocateScenario(Instant time) {
- for (int i = 0; i < 4; i++) {
- long count = update(
- "#Project.allocateScenario",
- Parameters.with("id", id).and("oldState", scenariosCreated).and("now", time));
- if (count > 0) {
- return scenariosCreated + 1;
- } else {
- Panache.getEntityManager().refresh(this);
- }
- }
-
- throw new IllegalStateException("Failed to allocate next scenario");
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java
deleted file mode 100644
index 3776ae12..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/ProjectAuthorization.java
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.Column;
-import jakarta.persistence.Embeddable;
-import jakarta.persistence.EmbeddedId;
-import jakarta.persistence.Entity;
-import jakarta.persistence.EnumType;
-import jakarta.persistence.Enumerated;
-import jakarta.persistence.FetchType;
-import jakarta.persistence.ForeignKey;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.ManyToOne;
-import jakarta.persistence.MapsId;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.Table;
-import java.io.Serializable;
-import java.util.Objects;
-import org.opendc.web.proto.user.ProjectRole;
-
-/**
- * An authorization for some user to participate in a project.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "ProjectAuthorization.findByUser",
- query =
- """
- SELECT a
- FROM ProjectAuthorization a
- WHERE a.key.userName = :userName
- """),
-})
-public class ProjectAuthorization extends PanacheEntityBase {
- /**
- * The user identifier of the authorization.
- */
- @EmbeddedId
- public ProjectAuthorization.Key key;
-
- /**
- * The project that the user is authorized to participate in.
- */
- @ManyToOne(optional = false, fetch = FetchType.LAZY)
- @MapsId("projectId")
- @JoinColumn(
- name = "project_id",
- updatable = false,
- insertable = false,
- nullable = false,
- foreignKey = @ForeignKey(name = "fk_project_authorizations"))
- public Project project;
-
- /**
- * The role of the user in the project.
- */
- @Column(nullable = false)
- @Enumerated(EnumType.STRING)
- public ProjectRole role;
-
- /**
- * Construct a {@link ProjectAuthorization} object.
- */
- public ProjectAuthorization(Project project, String userName, ProjectRole role) {
- this.key = new ProjectAuthorization.Key(project.id, userName);
- this.project = project;
- this.role = role;
- }
-
- /**
- * JPA constructor
- */
- protected ProjectAuthorization() {}
-
- /**
- * List all projects for the user with the specified <code>userName</code>.
- *
- * @param userName The identifier of the user that is requesting the list of projects.
- * @return A query returning projects that the user has received authorization for.
- */
- public static PanacheQuery<ProjectAuthorization> findByUser(String userName) {
- return find("#ProjectAuthorization.findByUser", Parameters.with("userName", userName));
- }
-
- /**
- * Find the project with <code>id</code> for the user with the specified <code>userName</code>.
- *
- * @param userName The identifier of the user that is requesting the list of projects.
- * @param project_id The unique identifier of the project.
- * @return The project with the specified identifier or <code>null</code> if it does not exist or is not accessible
- * to the user with the specified identifier.
- */
- public static ProjectAuthorization findByUser(String userName, long project_id) {
- return findById(new ProjectAuthorization.Key(project_id, userName));
- }
-
- /**
- * Determine whether the authorization allows the user to edit the project.
- */
- public boolean canEdit() {
- return switch (role) {
- case OWNER, EDITOR -> true;
- case VIEWER -> false;
- };
- }
-
- /**
- * Determine whether the authorization allows the user to delete the project.
- */
- public boolean canDelete() {
- return role == ProjectRole.OWNER;
- }
-
- /**
- * Key for representing a {@link ProjectAuthorization} object.
- */
- @Embeddable
- public static class Key implements Serializable {
- @Column(name = "project_id", nullable = false)
- public long projectId;
-
- @Column(name = "user_name", nullable = false)
- public String userName;
-
- public Key(long projectId, String userName) {
- this.projectId = projectId;
- this.userName = userName;
- }
-
- protected Key() {}
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- Key key = (Key) o;
- return projectId == key.projectId && userName.equals(key.userName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(projectId, userName);
- }
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java
deleted file mode 100644
index c79ef5bb..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Scenario.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.*;
-import java.util.ArrayList;
-import java.util.List;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.OperationalPhenomena;
-
-/**
- * A single scenario to be explored by the simulator.
- */
-@Entity
-@Table(
- uniqueConstraints = {
- @UniqueConstraint(
- name = "uk_scenarios_number",
- columnNames = {"project_id", "number"})
- },
- indexes = {@Index(name = "ux_scenarios_number", columnList = "project_id, number")})
-@NamedQueries({
- @NamedQuery(name = "Scenario.findByProject", query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId"),
- @NamedQuery(
- name = "Scenario.findByPortfolio",
- query =
- """
- SELECT s
- FROM Scenario s
- JOIN Portfolio p ON p.id = s.portfolio.id AND p.number = :number
- WHERE s.project.id = :projectId
- """),
- @NamedQuery(
- name = "Scenario.findOneByProject",
- query = "SELECT s FROM Scenario s WHERE s.project.id = :projectId AND s.number = :number")
-})
-public class Scenario extends PanacheEntityBase {
- /**
- * The main ID of a Scenario.
- * The value starts at 3 to account for the other 2 scenarios already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "scenarioSeq", sequenceName = "scenario_id_seq", allocationSize = 1, initialValue = 3)
- @GeneratedValue(generator = "scenarioSeq")
- public Long id;
-
- /**
- * The {@link Project} to which this scenario belongs.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "project_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_project"))
- public Project project;
-
- /**
- * The {@link Portfolio} to which this scenario belongs.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "portfolio_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_portfolio"))
- public Portfolio portfolio;
-
- /**
- * Unique number of the scenario for the project.
- */
- @Column(nullable = false)
- public int number;
-
- /**
- * The name of the scenario.
- */
- @Column(nullable = false, updatable = false)
- public String name;
-
- /**
- * Workload details of the scenario.
- */
- @Embedded
- public Workload workload;
-
- /**
- * Topology details of the scenario.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "topology_id", nullable = false, foreignKey = @ForeignKey(name = "fk_scenarios_topology"))
- public Topology topology;
-
- /**
- * Operational phenomena activated in the scenario.
- * @Column(columnDefinition = "jsonb", nullable = false, updatable = false)
- * @Type(JsonType.class)
- */
- @Column(columnDefinition = "jsonb", nullable = false, updatable = false)
- @Type(JsonType.class)
- public OperationalPhenomena phenomena;
-
- /**
- * The name of the VM scheduler used in the scenario.
- */
- @Column(name = "scheduler_name", nullable = false, updatable = false)
- public String schedulerName;
-
- /**
- * The {@link Job} associated with the scenario.
- */
- @OneToMany(
- cascade = {CascadeType.ALL},
- mappedBy = "scenario",
- fetch = FetchType.LAZY)
- public List<Job> jobs = new ArrayList<>();
-
- /**
- * Construct a {@link Scenario} object.
- */
- public Scenario(
- Project project,
- Portfolio portfolio,
- int number,
- String name,
- Workload workload,
- Topology topology,
- OperationalPhenomena phenomena,
- String schedulerName) {
- this.project = project;
- this.portfolio = portfolio;
- this.number = number;
- this.name = name;
- this.workload = workload;
- this.topology = topology;
- this.phenomena = phenomena;
- this.schedulerName = schedulerName;
- }
-
- /**
- * JPA constructor
- */
- protected Scenario() {}
-
- /**
- * Find all {@link Scenario}s that belong to the specified project
- *
- * @param projectId The unique identifier of the project.
- * @return The query of scenarios that belong to the specified project.
- */
- public static PanacheQuery<Scenario> findByProject(long projectId) {
- return find("#Scenario.findByProject", Parameters.with("projectId", projectId));
- }
-
- /**
- * Find all {@link Scenario}s that belong to the specified portfolio.
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the portfolio.
- * @return The query of scenarios that belong to the specified project and portfolio..
- */
- public static PanacheQuery<Scenario> findByPortfolio(long projectId, int number) {
- return find(
- "#Scenario.findByPortfolio",
- Parameters.with("projectId", projectId).and("number", number));
- }
-
- /**
- * Find the {@link Scenario} with the specified <code>number</code> belonging to the specified project.
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the scenario.
- * @return The scenario or <code>null</code> if it does not exist.
- */
- public static Scenario findByProject(long projectId, int number) {
- return find(
- "#Scenario.findOneByProject",
- Parameters.with("projectId", projectId).and("number", number))
- .firstResult();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java
deleted file mode 100644
index 8a4e2ae2..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Topology.java
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.hypersistence.utils.hibernate.type.json.JsonType;
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.hibernate.orm.panache.PanacheQuery;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.GeneratedValue;
-import jakarta.persistence.Id;
-import jakarta.persistence.Index;
-import jakarta.persistence.JoinColumn;
-import jakarta.persistence.ManyToOne;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.SequenceGenerator;
-import jakarta.persistence.Table;
-import jakarta.persistence.UniqueConstraint;
-import java.time.Instant;
-import java.util.List;
-import org.hibernate.annotations.Type;
-import org.opendc.web.proto.Room;
-
-/**
- * A datacenter design in OpenDC.
- */
-@Entity
-@Table(
- uniqueConstraints = {
- @UniqueConstraint(
- name = "uk_topologies_number",
- columnNames = {"project_id", "number"})
- },
- indexes = {@Index(name = "ux_topologies_number", columnList = "project_id, number")})
-@NamedQueries({
- @NamedQuery(name = "Topology.findByProject", query = "SELECT t FROM Topology t WHERE t.project.id = :projectId"),
- @NamedQuery(
- name = "Topology.findOneByProject",
- query = "SELECT t FROM Topology t WHERE t.project.id = :projectId AND t.number = :number")
-})
-public class Topology extends PanacheEntityBase {
- /**
- * The main ID of a project.
- * The value starts at 6 to account for the other 5 projects already made by the loading script.
- */
- @Id
- @SequenceGenerator(name = "topologySeq", sequenceName = "topology_id_seq", allocationSize = 1, initialValue = 5)
- @GeneratedValue(generator = "topologySeq")
- public Long id;
-
- /**
- * The {@link Project} to which the topology belongs.
- */
- @ManyToOne(optional = false)
- @JoinColumn(name = "project_id", nullable = false)
- public Project project;
-
- /**
- * Unique number of the topology for the project.
- */
- @Column(nullable = false)
- public int number;
-
- /**
- * The name of the topology.
- */
- @Column(nullable = false)
- public String name;
-
- /**
- * The instant at which the topology was created.
- */
- @Column(name = "created_at", nullable = false, updatable = false)
- public Instant createdAt;
-
- /**
- * The instant at which the topology was updated.
- */
- @Column(name = "updated_at", nullable = false)
- public Instant updatedAt;
-
- /**
- * Datacenter design in JSON
- * @Column(columnDefinition = "jsonb", nullable = false)
- * @Type(JsonType.class)
- */
- @Column(columnDefinition = "jsonb", nullable = false)
- @Type(JsonType.class)
- public List<Room> rooms;
-
- /**
- * Construct a {@link Topology} object.
- */
- public Topology(Project project, int number, String name, Instant createdAt, List<Room> rooms) {
- this.project = project;
- this.number = number;
- this.name = name;
- this.createdAt = createdAt;
- this.updatedAt = createdAt;
- this.rooms = rooms;
- }
-
- /**
- * JPA constructor
- */
- protected Topology() {}
-
- /**
- * Find all [Topology]s that belong to [project][projectId].
- *
- * @param projectId The unique identifier of the project.
- * @return The query of topologies that belong to the specified project.
- */
- public static PanacheQuery<Topology> findByProject(long projectId) {
- return find("#Topology.findByProject", Parameters.with("projectId", projectId));
- }
-
- /**
- * Find the [Topology] with the specified [number] belonging to [project][projectId].
- *
- * @param projectId The unique identifier of the project.
- * @param number The number of the topology.
- * @return The topology or `null` if it does not exist.
- */
- public static Topology findByProject(long projectId, int number) {
- return find(
- "#Topology.findOneByProject",
- Parameters.with("projectId", projectId).and("number", number))
- .firstResult();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java
deleted file mode 100644
index 71c647bc..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Trace.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.Table;
-
-/**
- * A workload trace available for simulation.
- */
-@Entity
-@Table
-public class Trace extends PanacheEntityBase {
- /**
- * The unique identifier of the trace.
- */
- @Id
- public String id;
-
- /**
- * The name of the trace.
- */
- @Column(nullable = false, updatable = false)
- public String name;
-
- /**
- * The type of trace.
- */
- @Column(nullable = false, updatable = false)
- public String type;
-
- /**
- * Construct a {@link Trace}.
- *
- * @param id The unique identifier of the trace.
- * @param name The name of the trace.
- * @param type The type of trace.
- */
- public Trace(String id, String name, String type) {
- this.id = id;
- this.name = name;
- this.type = type;
- }
-
- /**
- * JPA constructor.
- */
- protected Trace() {}
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java
deleted file mode 100644
index 10a10ef9..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/UserAccounting.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import io.quarkus.hibernate.orm.panache.PanacheEntityBase;
-import io.quarkus.panache.common.Parameters;
-import jakarta.persistence.Column;
-import jakarta.persistence.Entity;
-import jakarta.persistence.Id;
-import jakarta.persistence.NamedQueries;
-import jakarta.persistence.NamedQuery;
-import jakarta.persistence.Table;
-import java.time.LocalDate;
-
-/**
- * Entity to track the number of simulation minutes used by a user.
- */
-@Entity
-@Table
-@NamedQueries({
- @NamedQuery(
- name = "UserAccounting.consumeBudget",
- query =
- """
- UPDATE UserAccounting a
- SET a.simulationTime = a.simulationTime + :seconds
- WHERE a.userId = :userId AND a.periodEnd = :periodEnd
- """),
- @NamedQuery(
- name = "UserAccounting.resetBudget",
- query =
- """
- UPDATE UserAccounting a
- SET a.periodEnd = :periodEnd, a.simulationTime = :seconds
- WHERE a.userId = :userId AND a.periodEnd = :oldPeriodEnd
- """)
-})
-public class UserAccounting extends PanacheEntityBase {
- /**
- * User to which this object belongs.
- */
- @Id
- @Column(name = "user_id", nullable = false)
- public String userId;
-
- /**
- * The end of the accounting period.
- */
- @Column(name = "period_end", nullable = false)
- public LocalDate periodEnd;
-
- /**
- * The number of simulation seconds to be used per accounting period.
- */
- @Column(name = "simulation_time_budget", nullable = false)
- public int simulationTimeBudget;
-
- /**
- * The number of simulation seconds used in this period. This number should reset once the accounting period has
- * been reached.
- */
- @Column(name = "simulation_time", nullable = false)
- public int simulationTime = 0;
-
- /**
- * Construct a new {@link UserAccounting} object.
- *
- * @param userId The identifier of the user that this object belongs to.
- * @param periodEnd The end of the accounting period.
- * @param simulationTimeBudget The number of simulation seconds available per accounting period.
- */
- public UserAccounting(String userId, LocalDate periodEnd, int simulationTimeBudget) {
- this.userId = userId;
- this.periodEnd = periodEnd;
- this.simulationTimeBudget = simulationTimeBudget;
- }
-
- /**
- * JPA constructor.
- */
- protected UserAccounting() {}
-
- /**
- * Return the {@link UserAccounting} object associated with the specified user id.
- */
- public static UserAccounting findByUser(String userId) {
- return findById(userId);
- }
-
- /**
- * Create a new {@link UserAccounting} object and persist it to the database.
- *
- * @param userId The identifier of the user that this object belongs to.
- * @param periodEnd The end of the accounting period.
- * @param simulationTimeBudget The number of simulation seconds available per accounting period.
- * @param simulationTime The initial simulation time that has been consumed.
- */
- public static UserAccounting create(
- String userId, LocalDate periodEnd, int simulationTimeBudget, int simulationTime) {
- UserAccounting newAccounting = new UserAccounting(userId, periodEnd, simulationTimeBudget);
- newAccounting.simulationTime = simulationTime;
- newAccounting.persistAndFlush();
- return newAccounting;
- }
-
- /**
- * Atomically consume the budget for this {@link UserAccounting} object.
- *
- * @param seconds The number of seconds to consume from the user.
- * @return <code>true</code> when the update succeeded, <code>false</code> when there was a conflict.
- */
- public boolean consumeBudget(int seconds) {
- long count = update(
- "#UserAccounting.consumeBudget",
- Parameters.with("userId", userId).and("periodEnd", periodEnd).and("seconds", seconds));
- return count > 0;
- }
-
- /**
- * Atomically reset the budget for this {@link UserAccounting} object.
- *
- * @param periodEnd The new end period for the budget.
- * @param seconds The number of seconds that have already been consumed.
- * @return <code>true</code> when the update succeeded`, <code>false</code> when there was a conflict.
- */
- public boolean resetBudget(LocalDate periodEnd, int seconds) {
- long count = update(
- "#UserAccounting.resetBudget",
- Parameters.with("userId", userId)
- .and("oldPeriodEnd", this.periodEnd)
- .and("periodEnd", periodEnd)
- .and("seconds", seconds));
- return count > 0;
- }
-
- /**
- * Determine whether the user has any remaining simulation budget.
- *
- * @return <code>true</code> when the user still has budget left, <code>false</code> otherwise.
- */
- public boolean hasSimulationBudget() {
- var today = LocalDate.now();
-
- // The accounting period must be over or there must be budget remaining.
- return !today.isBefore(periodEnd) || simulationTimeBudget > simulationTime;
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java
deleted file mode 100644
index fd7010d2..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/model/Workload.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.model;
-
-import jakarta.persistence.Column;
-import jakarta.persistence.Embeddable;
-import jakarta.persistence.ManyToOne;
-
-/**
- * Specification of the workload for a {@link Scenario}
- */
-@Embeddable
-public class Workload {
- /**
- * The {@link Trace} that the workload runs.
- */
- @ManyToOne(optional = false)
- public Trace trace;
-
- /**
- * The percentage of the trace that should be sampled.
- */
- @Column(name = "sampling_fraction", nullable = false, updatable = false)
- public double samplingFraction;
-
- /**
- * Construct a {@link Workload} object.
- *
- * @param trace The {@link Trace} to run as workload.
- * @param samplingFraction The percentage of the workload to sample.
- */
- public Workload(Trace trace, double samplingFraction) {
- this.trace = trace;
- this.samplingFraction = samplingFraction;
- }
-
- /**
- * JPA constructor.
- */
- protected Workload() {}
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java
deleted file mode 100644
index 44d2d569..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/BaseProtocol.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import org.opendc.web.server.model.Trace;
-import org.opendc.web.server.model.Workload;
-
-/**
- * DTO-conversions for the base protocol.
- */
-public final class BaseProtocol {
- /**
- * Private constructor to prevent instantiation of class.
- */
- private BaseProtocol() {}
-
- /**
- * Convert a {@link Workload} entity into a DTO.
- */
- public static org.opendc.web.proto.Workload toDto(Workload workload) {
- return new org.opendc.web.proto.Workload(toDto(workload.trace), workload.samplingFraction);
- }
-
- /**
- * Convert a {@link Trace] entity into a {@link org.opendc.web.proto.Trace} DTO.
- */
- public static org.opendc.web.proto.Trace toDto(Trace trace) {
- return new org.opendc.web.proto.Trace(trace.id, trace.name, trace.type);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java
deleted file mode 100644
index 3e839040..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/SchedulerResource.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.Produces;
-import java.util.List;
-
-/**
- * A resource representing the available schedulers that can be used during experiments.
- */
-@Produces("application/json")
-@Path("/schedulers")
-public final class SchedulerResource {
- /**
- * Obtain all available schedulers.
- */
- @GET
- public List<String> getAll() {
- return List.of(
- "mem",
- "mem-inv",
- "core-mem",
- "core-mem-inv",
- "active-tasks",
- "active-tasks-inv",
- "provisioned-cores",
- "provisioned-cores-inv",
- "random");
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java
deleted file mode 100644
index daec01cd..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/TraceResource.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.util.List;
-import java.util.stream.Stream;
-import org.opendc.web.server.model.Trace;
-
-/**
- * A resource representing the workload traces available in the OpenDC instance.
- */
-@Produces("application/json")
-@Path("/traces")
-public final class TraceResource {
- /**
- * Obtain all available traces.
- */
- @GET
- public List<org.opendc.web.proto.Trace> getAll() {
- Stream<Trace> entities = Trace.streamAll();
- return entities.map(TraceResource::toDto).toList();
- }
-
- /**
- * Obtain trace information by identifier.
- */
- @GET
- @Path("{id}")
- public org.opendc.web.proto.Trace get(@PathParam("id") String id) {
- Trace trace = Trace.findById(id);
-
- if (trace == null) {
- throw new WebApplicationException("Trace not found", 404);
- }
-
- return toDto(trace);
- }
-
- /**
- * Convert a {@link Trace] entity into a {@link org.opendc.web.proto.Trace} DTO.
- */
- public static org.opendc.web.proto.Trace toDto(Trace trace) {
- return new org.opendc.web.proto.Trace(trace.id, trace.name, trace.type);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java
deleted file mode 100644
index 345acdfe..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/MissingKotlinParameterExceptionMapper.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.error;
-
-import com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.ext.ExceptionMapper;
-import jakarta.ws.rs.ext.Provider;
-import org.opendc.web.proto.ProtocolError;
-
-/**
- * An [ExceptionMapper] for [MissingKotlinParameterException] thrown by Jackson.
- */
-@Provider
-public final class MissingKotlinParameterExceptionMapper implements ExceptionMapper<MissingKotlinParameterException> {
- @Override
- public Response toResponse(MissingKotlinParameterException exception) {
- return Response.status(Response.Status.BAD_REQUEST)
- .entity(new ProtocolError(
- Response.Status.BAD_REQUEST.getStatusCode(),
- "Field " + exception.getParameter().getName() + " is missing from body."))
- .type(MediaType.APPLICATION_JSON)
- .build();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java
deleted file mode 100644
index e027e559..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/error/WebApplicationExceptionMapper.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.error;
-
-import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
-import jakarta.ws.rs.ext.ExceptionMapper;
-import jakarta.ws.rs.ext.Provider;
-import org.opendc.web.proto.ProtocolError;
-
-/**
- * Helper class to transform a {@link WebApplicationException} into an JSON error response.
- */
-@Provider
-public final class WebApplicationExceptionMapper implements ExceptionMapper<WebApplicationException> {
- @Override
- public Response toResponse(WebApplicationException exception) {
- int code = exception.getResponse().getStatus();
-
- String message = exception.getMessage();
- if (message == null) {
- message = "Unknown error";
- }
-
- return Response.status(code)
- .entity(new ProtocolError(code, message))
- .type(MediaType.APPLICATION_JSON)
- .build();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java
deleted file mode 100644
index 4dde8654..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/JobResource.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.runner;
-
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.util.List;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.service.JobService;
-
-/**
- * A resource representing the available simulation jobs.
- */
-@Produces("application/json")
-@Path("/jobs")
-@RolesAllowed("runner")
-public final class JobResource {
- /**
- * The {@link JobService} for helping manage the job lifecycle.
- */
- private final JobService jobService;
-
- /**
- * Construct a {@link JobResource} instance.
- *
- * @param jobService The {@link JobService} for managing the job lifecycle.
- */
- public JobResource(JobService jobService) {
- this.jobService = jobService;
- }
-
- /**
- * Obtain all pending simulation jobs.
- */
- @GET
- public List<org.opendc.web.proto.runner.Job> queryPending() {
- return Job.findByState(JobState.PENDING).list().stream()
- .map(RunnerProtocol::toDto)
- .toList();
- }
-
- /**
- * Get a job by identifier.
- */
- @GET
- @Path("{job}")
- public org.opendc.web.proto.runner.Job get(@PathParam("job") long id) {
- Job job = Job.findById(id);
-
- if (job == null) {
- throw new WebApplicationException("Job not found", 404);
- }
-
- return RunnerProtocol.toDto(job);
- }
-
- /**
- * Atomically update the state of a job.
- */
- @POST
- @Path("{job}")
- @Consumes("application/json")
- @Transactional
- public org.opendc.web.proto.runner.Job update(
- @PathParam("job") long id, @Valid org.opendc.web.proto.runner.Job.Update update) {
- Job job = Job.findById(id);
- if (job == null) {
- throw new WebApplicationException("Job not found", 404);
- }
-
- try {
- jobService.updateJob(job, update.getState(), update.getRuntime(), update.getResults());
- } catch (IllegalArgumentException e) {
- throw new WebApplicationException(e, 400);
- } catch (IllegalStateException e) {
- throw new WebApplicationException(e, 409);
- }
-
- return RunnerProtocol.toDto(job);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java
deleted file mode 100644
index 6bf65d97..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/runner/RunnerProtocol.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.runner;
-
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.Scenario;
-import org.opendc.web.server.model.Topology;
-import org.opendc.web.server.rest.BaseProtocol;
-
-/**
- * DTO-conversions for the runner protocol.
- */
-public final class RunnerProtocol {
- /**
- * Private constructor to prevent instantiation of class.
- */
- private RunnerProtocol() {}
-
- /**
- * Convert a {@link Job} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Job toDto(Job job) {
- return new org.opendc.web.proto.runner.Job(
- job.id, toDto(job.scenario), job.state, job.createdAt, job.updatedAt, job.runtime, job.results);
- }
-
- /**
- * Convert a {@link Scenario} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Scenario toDto(Scenario scenario) {
- return new org.opendc.web.proto.runner.Scenario(
- scenario.id,
- scenario.number,
- toDto(scenario.portfolio),
- scenario.name,
- BaseProtocol.toDto(scenario.workload),
- toDto(scenario.topology),
- scenario.phenomena,
- scenario.schedulerName);
- }
-
- /**
- * Convert a {@link Portfolio} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Portfolio toDto(Portfolio portfolio) {
- return new org.opendc.web.proto.runner.Portfolio(
- portfolio.id, portfolio.number, portfolio.name, portfolio.targets);
- }
-
- /**
- * Convert a {@link Topology} into a runner-facing DTO.
- */
- public static org.opendc.web.proto.runner.Topology toDto(Topology topology) {
- return new org.opendc.web.proto.runner.Topology(
- topology.id, topology.number, topology.name, topology.rooms, topology.createdAt, topology.updatedAt);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java
deleted file mode 100644
index 2a3a40f4..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioResource.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.ProjectAuthorization;
-
-/**
- * A resource representing the portfolios of a project.
- */
-@Produces("application/json")
-@Path("/projects/{project}/portfolios")
-@RolesAllowed("openid")
-public final class PortfolioResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link PortfolioResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public PortfolioResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Get all portfolios that belong to the specified project.
- */
- @GET
- public List<org.opendc.web.proto.user.Portfolio> getAll(@PathParam("project") long projectId) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- return List.of();
- }
-
- return Portfolio.findByProject(projectId).list().stream()
- .map((p) -> UserProtocol.toDto(p, auth))
- .toList();
- }
-
- /**
- * Create a portfolio for this project.
- */
- @POST
- @Transactional
- @Consumes("application/json")
- public org.opendc.web.proto.user.Portfolio create(
- @PathParam("project") long projectId, @Valid org.opendc.web.proto.user.Portfolio.Create request) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- var now = Instant.now();
- var project = auth.project;
- int number = project.allocatePortfolio(now);
-
- Portfolio portfolio = new Portfolio(project, number, request.getName(), request.getTargets());
-
- project.portfolios.add(portfolio);
- portfolio.persist();
-
- return UserProtocol.toDto(portfolio, auth);
- }
-
- /**
- * Obtain a portfolio by its identifier.
- */
- @GET
- @Path("{portfolio}")
- public org.opendc.web.proto.user.Portfolio get(
- @PathParam("project") long projectId, @PathParam("portfolio") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- Portfolio portfolio = Portfolio.findByProject(projectId, number);
-
- if (portfolio == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- return UserProtocol.toDto(portfolio, auth);
- }
-
- /**
- * Delete a portfolio.
- */
- @DELETE
- @Path("{portfolio}")
- @Transactional
- public org.opendc.web.proto.user.Portfolio delete(
- @PathParam("project") long projectId, @PathParam("portfolio") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Portfolio entity = Portfolio.findByProject(projectId, number);
- if (entity == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- entity.delete();
- return UserProtocol.toDto(entity, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java
deleted file mode 100644
index 789808c8..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/PortfolioScenarioResource.java
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Scenario;
-import org.opendc.web.server.model.Topology;
-import org.opendc.web.server.model.Trace;
-import org.opendc.web.server.model.Workload;
-import org.opendc.web.server.service.UserAccountingService;
-
-/**
- * A resource representing the scenarios of a portfolio.
- */
-@Path("/projects/{project}/portfolios/{portfolio}/scenarios")
-@RolesAllowed("openid")
-@Produces("application/json")
-public final class PortfolioScenarioResource {
- /**
- * The service for managing the user accounting.
- */
- private final UserAccountingService accountingService;
-
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link PortfolioScenarioResource}.
- *
- * @param accountingService The {@link UserAccountingService} instance to use.
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public PortfolioScenarioResource(UserAccountingService accountingService, SecurityIdentity identity) {
- this.accountingService = accountingService;
- this.identity = identity;
- }
-
- /**
- * Get all scenarios that belong to the specified portfolio.
- */
- @GET
- public List<org.opendc.web.proto.user.Scenario> get(
- @PathParam("project") long projectId, @PathParam("portfolio") int portfolioNumber) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- return List.of();
- }
-
- return org.opendc.web.server.model.Scenario.findByPortfolio(projectId, portfolioNumber).list().stream()
- .map((s) -> UserProtocol.toDto(s, auth))
- .toList();
- }
-
- /**
- * Create a scenario for this portfolio.
- */
- @POST
- @Transactional
- @Consumes("application/json")
- public org.opendc.web.proto.user.Scenario create(
- @PathParam("project") long projectId,
- @PathParam("portfolio") int portfolioNumber,
- @Valid org.opendc.web.proto.user.Scenario.Create request) {
- // User must have access to project
- String userId = identity.getPrincipal().getName();
- ProjectAuthorization auth = ProjectAuthorization.findByUser(userId, projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Portfolio portfolio = Portfolio.findByProject(projectId, portfolioNumber);
-
- if (portfolio == null) {
- throw new WebApplicationException("Portfolio not found", 404);
- }
-
- Topology topology = Topology.findByProject(projectId, (int) request.getTopology());
- if (topology == null) {
- throw new WebApplicationException("Referred topology does not exist", 400);
- }
-
- Trace trace = Trace.findById(request.getWorkload().getTrace());
- if (trace == null) {
- throw new WebApplicationException("Referred trace does not exist", 400);
- }
-
- var now = Instant.now();
- var project = auth.project;
- int number = project.allocateScenario(now);
-
- Scenario scenario = new Scenario(
- project,
- portfolio,
- number,
- request.getName(),
- new Workload(trace, request.getWorkload().getSamplingFraction()),
- topology,
- request.getPhenomena(),
- request.getSchedulerName());
- scenario.persist();
-
- Job job = new Job(scenario, userId, now, portfolio.targets.getRepeats());
- job.persist();
-
- // Fail the job if there is not enough budget for the simulation
- if (!accountingService.hasSimulationBudget(userId)) {
- job.state = JobState.FAILED;
- }
-
- scenario.jobs.add(job);
- portfolio.scenarios.add(scenario);
-
- return UserProtocol.toDto(scenario, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java
deleted file mode 100644
index ae1c959e..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ProjectResource.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.proto.user.ProjectRole;
-import org.opendc.web.server.model.Project;
-import org.opendc.web.server.model.ProjectAuthorization;
-
-/**
- * A resource representing the created projects.
- */
-@Produces("application/json")
-@Path("/projects")
-@RolesAllowed("openid")
-public final class ProjectResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link ProjectResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public ProjectResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Obtain all the projects of the current user.
- */
- @GET
- public List<org.opendc.web.proto.user.Project> getAll() {
- return ProjectAuthorization.findByUser(identity.getPrincipal().getName()).list().stream()
- .map(UserProtocol::toDto)
- .toList();
- }
-
- /**
- * Create a new project for the current user.
- */
- @POST
- @Transactional
- @Consumes("application/json")
- public org.opendc.web.proto.user.Project create(@Valid org.opendc.web.proto.user.Project.Create request) {
- Instant now = Instant.now();
- Project entity = new Project(request.getName(), now);
- entity.persist();
-
- ProjectAuthorization authorization =
- new ProjectAuthorization(entity, identity.getPrincipal().getName(), ProjectRole.OWNER);
-
- entity.authorizations.add(authorization);
- authorization.persist();
-
- return UserProtocol.toDto(authorization);
- }
-
- /**
- * Obtain a single project by its identifier.
- */
- @GET
- @Path("{project}")
- public org.opendc.web.proto.user.Project get(@PathParam("project") long project_id) {
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), project_id);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- }
-
- return UserProtocol.toDto(auth);
- }
-
- /**
- * Delete a project.
- */
- @DELETE
- @Path("{project}")
- @Transactional
- public org.opendc.web.proto.user.Project delete(@PathParam("project") long id) {
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), id);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- } else if (!auth.canDelete()) {
- throw new WebApplicationException("Not allowed to delete project", 403);
- }
-
- auth.project.updatedAt = Instant.now();
- org.opendc.web.proto.user.Project project = UserProtocol.toDto(auth);
- auth.project.delete();
- return project;
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java
deleted file mode 100644
index bb3eb89b..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/ScenarioResource.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.transaction.Transactional;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.util.List;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Scenario;
-
-/**
- * A resource representing the scenarios of a portfolio.
- */
-@Produces("application/json")
-@Path("/projects/{project}/scenarios")
-@RolesAllowed("openid")
-public final class ScenarioResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link ScenarioResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public ScenarioResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Obtain the scenarios belonging to a project.
- */
- @GET
- public List<org.opendc.web.proto.user.Scenario> getAll(@PathParam("project") long projectId) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- }
-
- return Scenario.findByProject(projectId).list().stream()
- .map((s) -> UserProtocol.toDto(s, auth))
- .toList();
- }
-
- /**
- * Obtain a scenario by its identifier.
- */
- @GET
- @Path("{scenario}")
- public org.opendc.web.proto.user.Scenario get(
- @PathParam("project") long projectId, @PathParam("scenario") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- }
-
- Scenario scenario = Scenario.findByProject(projectId, number);
-
- if (scenario == null) {
- throw new WebApplicationException("Scenario not found", 404);
- }
-
- return UserProtocol.toDto(scenario, auth);
- }
-
- /**
- * Delete a scenario.
- */
- @DELETE
- @Path("{scenario}")
- @Transactional
- public org.opendc.web.proto.user.Scenario delete(
- @PathParam("project") long projectId, @PathParam("scenario") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Project not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Scenario entity = Scenario.findByProject(projectId, number);
- if (entity == null) {
- throw new WebApplicationException("Scenario not found", 404);
- }
-
- entity.delete();
- return UserProtocol.toDto(entity, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java
deleted file mode 100644
index b8c542d3..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/TopologyResource.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.hibernate.orm.panache.Panache;
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.persistence.PersistenceException;
-import jakarta.transaction.Transactional;
-import jakarta.validation.Valid;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.PUT;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import java.time.Instant;
-import java.util.List;
-import org.opendc.web.server.model.Project;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Topology;
-
-/**
- * A resource representing the constructed datacenter topologies.
- */
-@Produces("application/json")
-@Path("/projects/{project}/topologies")
-@RolesAllowed("openid")
-public final class TopologyResource {
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link TopologyResource}.
- *
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public TopologyResource(SecurityIdentity identity) {
- this.identity = identity;
- }
-
- /**
- * Get all topologies that belong to the specified project.
- */
- @GET
- public List<org.opendc.web.proto.user.Topology> getAll(@PathParam("project") long projectId) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- return List.of();
- }
-
- return Topology.findByProject(projectId).list().stream()
- .map((t) -> UserProtocol.toDto(t, auth))
- .toList();
- }
-
- /**
- * Create a topology for this project.
- */
- @POST
- @Consumes("application/json")
- @Transactional
- public org.opendc.web.proto.user.Topology create(
- @PathParam("project") long projectId, @Valid org.opendc.web.proto.user.Topology.Create request) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Instant now = Instant.now();
- Project project = auth.project;
- int number = project.allocateTopology(now);
-
- Topology topology = new Topology(project, number, request.getName(), now, request.getRooms());
-
- project.topologies.add(topology);
- topology.persist();
-
- return UserProtocol.toDto(topology, auth);
- }
-
- /**
- * Obtain a topology by its number.
- */
- @GET
- @Path("{topology}")
- public org.opendc.web.proto.user.Topology get(
- @PathParam("project") long projectId, @PathParam("topology") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- Topology topology = Topology.findByProject(projectId, number);
-
- if (topology == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- return UserProtocol.toDto(topology, auth);
- }
-
- /**
- * Update the specified topology by its number.
- */
- @PUT
- @Path("{topology}")
- @Consumes("application/json")
- @Transactional
- public org.opendc.web.proto.user.Topology update(
- @PathParam("project") long projectId,
- @PathParam("topology") int number,
- @Valid org.opendc.web.proto.user.Topology.Update request) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Topology entity = Topology.findByProject(projectId, number);
-
- if (entity == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- entity.updatedAt = Instant.now();
- entity.rooms = request.getRooms();
-
- return UserProtocol.toDto(entity, auth);
- }
-
- /**
- * Delete the specified topology.
- */
- @Path("{topology}")
- @DELETE
- @Transactional
- public org.opendc.web.proto.user.Topology delete(
- @PathParam("project") long projectId, @PathParam("topology") int number) {
- // User must have access to project
- ProjectAuthorization auth =
- ProjectAuthorization.findByUser(identity.getPrincipal().getName(), projectId);
-
- if (auth == null) {
- throw new WebApplicationException("Topology not found", 404);
- } else if (!auth.canEdit()) {
- throw new WebApplicationException("Not permitted to edit project", 403);
- }
-
- Topology entity = Topology.findByProject(projectId, number);
-
- if (entity == null) {
- throw new WebApplicationException("Topology not found", 404);
- }
-
- entity.updatedAt = Instant.now();
- entity.delete();
-
- try {
- // Flush the results, so we can check whether the constraints are not violated
- Panache.flush();
- } catch (PersistenceException e) {
- throw new WebApplicationException("Topology is still in use", 403);
- }
-
- return UserProtocol.toDto(entity, auth);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java
deleted file mode 100644
index 8196a9d6..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserProtocol.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.model.Portfolio;
-import org.opendc.web.server.model.Project;
-import org.opendc.web.server.model.ProjectAuthorization;
-import org.opendc.web.server.model.Scenario;
-import org.opendc.web.server.model.Topology;
-import org.opendc.web.server.rest.BaseProtocol;
-
-/**
- * DTO-conversions for the user protocol.
- */
-public final class UserProtocol {
- /**
- * Private constructor to prevent instantiation of class.
- */
- private UserProtocol() {}
-
- /**
- * Convert a {@link ProjectAuthorization} entity into a {@link Project} DTO.
- */
- public static org.opendc.web.proto.user.Project toDto(ProjectAuthorization auth) {
- Project project = auth.project;
- return new org.opendc.web.proto.user.Project(
- project.id, project.name, project.createdAt, project.updatedAt, auth.role);
- }
-
- /**
- * Convert a {@link Portfolio} entity into a {@link org.opendc.web.proto.user.Portfolio} DTO.
- */
- public static org.opendc.web.proto.user.Portfolio toDto(Portfolio portfolio, ProjectAuthorization auth) {
- return new org.opendc.web.proto.user.Portfolio(
- portfolio.id,
- portfolio.number,
- toDto(auth),
- portfolio.name,
- portfolio.targets,
- portfolio.scenarios.stream().map(UserProtocol::toSummaryDto).toList());
- }
-
- /**
- * Convert a {@link Portfolio} entity into a {@link org.opendc.web.proto.user.Portfolio.Summary} DTO.
- */
- public static org.opendc.web.proto.user.Portfolio.Summary toSummaryDto(Portfolio portfolio) {
- return new org.opendc.web.proto.user.Portfolio.Summary(
- portfolio.id, portfolio.number, portfolio.name, portfolio.targets);
- }
-
- /**
- * Convert a {@link Topology} entity into a {@link org.opendc.web.proto.user.Topology} DTO.
- */
- public static org.opendc.web.proto.user.Topology toDto(Topology topology, ProjectAuthorization auth) {
- return new org.opendc.web.proto.user.Topology(
- topology.id,
- topology.number,
- toDto(auth),
- topology.name,
- topology.rooms,
- topology.createdAt,
- topology.updatedAt);
- }
-
- /**
- * Convert a {@link Topology} entity into a {@link org.opendc.web.proto.user.Topology.Summary} DTO.
- */
- public static org.opendc.web.proto.user.Topology.Summary toSummaryDto(Topology topology) {
- return new org.opendc.web.proto.user.Topology.Summary(
- topology.id, topology.number, topology.name, topology.createdAt, topology.updatedAt);
- }
-
- /**
- * Convert a {@link Scenario} entity into a {@link org.opendc.web.proto.user.Scenario} DTO.
- */
- public static org.opendc.web.proto.user.Scenario toDto(Scenario scenario, ProjectAuthorization auth) {
- return new org.opendc.web.proto.user.Scenario(
- scenario.id,
- scenario.number,
- toDto(auth),
- toSummaryDto(scenario.portfolio),
- scenario.name,
- BaseProtocol.toDto(scenario.workload),
- toSummaryDto(scenario.topology),
- scenario.phenomena,
- scenario.schedulerName,
- scenario.jobs.stream().map(UserProtocol::toDto).toList());
- }
-
- /**
- * Convert a {@link Scenario} entity into a {@link org.opendc.web.proto.user.Scenario.Summary} DTO.
- */
- public static org.opendc.web.proto.user.Scenario.Summary toSummaryDto(Scenario scenario) {
- return new org.opendc.web.proto.user.Scenario.Summary(
- scenario.id,
- scenario.number,
- scenario.name,
- BaseProtocol.toDto(scenario.workload),
- toSummaryDto(scenario.topology),
- scenario.phenomena,
- scenario.schedulerName,
- scenario.jobs.stream().map(UserProtocol::toDto).toList());
- }
-
- /**
- * Convert a {@link Job} entity into a {@link org.opendc.web.proto.user.Job} DTO.
- */
- public static org.opendc.web.proto.user.Job toDto(Job job) {
- return new org.opendc.web.proto.user.Job(job.id, job.state, job.createdAt, job.updatedAt, job.results);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java
deleted file mode 100644
index c8cda2b7..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/rest/user/UserResource.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import io.quarkus.security.identity.SecurityIdentity;
-import jakarta.annotation.security.RolesAllowed;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.Produces;
-import org.opendc.web.proto.user.User;
-import org.opendc.web.proto.user.UserAccounting;
-import org.opendc.web.server.service.UserAccountingService;
-
-/**
- * A resource representing the active user.
- */
-@Produces("application/json")
-@Path("/users")
-@RolesAllowed("openid")
-public final class UserResource {
- /**
- * The service for managing the user accounting.
- */
- private final UserAccountingService accountingService;
-
- /**
- * The identity of the current user.
- */
- private final SecurityIdentity identity;
-
- /**
- * Construct a {@link UserResource}.
- *
- * @param accountingService The {@link UserAccountingService} instance to use.
- * @param identity The {@link SecurityIdentity} of the current user.
- */
- public UserResource(UserAccountingService accountingService, SecurityIdentity identity) {
- this.accountingService = accountingService;
- this.identity = identity;
- }
-
- /**
- * Get the current active user data.
- */
- @GET
- @Path("me")
- public User get() {
- String userId = identity.getPrincipal().getName();
- UserAccounting accounting = accountingService.getAccounting(userId);
-
- return new User(userId, accounting);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java
deleted file mode 100644
index 70933520..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/JobService.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.service;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import java.time.Instant;
-import java.util.Map;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.server.model.Job;
-
-/**
- * A service for managing the lifecycle of a job and ensuring that the user does not consume
- * too much simulation resources.
- */
-@ApplicationScoped
-public final class JobService {
- /**
- * The {@link UserAccountingService} responsible for accounting the simulation time of users.
- */
- private final UserAccountingService accountingService;
-
- /**
- * Construct a {@link JobService} instance.
- *
- * @param accountingService The {@link UserAccountingService} for accounting the simulation time of users.
- */
- public JobService(UserAccountingService accountingService) {
- this.accountingService = accountingService;
- }
-
- /**
- * Update the job state.
- *
- * @param job The {@link Job} to update.
- * @param newState The new state to transition the job to.
- * @param runtime The runtime (in seconds) consumed by the simulation jbo so far.
- * @param results The results to attach to the job.
- * @throws IllegalArgumentException if the state transition is invalid.
- * @throws IllegalStateException if someone tries to update the job concurrently.
- */
- public void updateJob(Job job, JobState newState, int runtime, Map<String, ?> results) {
- JobState state = job.state;
-
- if (!job.canTransitionTo(newState)) {
- throw new IllegalArgumentException("Invalid transition from %s to %s".formatted(state, newState));
- }
-
- Instant now = Instant.now();
- JobState nextState = newState;
- int consumedBudget = Math.min(1, runtime - job.runtime);
-
- // Check whether the user still has any simulation budget left
- if (accountingService.consumeSimulationBudget(job.createdBy, consumedBudget) && nextState == JobState.RUNNING) {
- nextState = JobState.FAILED; // User has consumed all their budget; cancel the job
- }
-
- if (!job.updateAtomically(nextState, now, runtime, results)) {
- throw new IllegalStateException("Conflicting update");
- }
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java
deleted file mode 100644
index 73fa2a3e..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/service/UserAccountingService.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.service;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.persistence.EntityExistsException;
-import java.time.Duration;
-import java.time.LocalDate;
-import java.time.temporal.TemporalAdjusters;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.opendc.web.server.model.UserAccounting;
-
-/**
- * Service to track the simulation budget of users.
- */
-@ApplicationScoped
-public final class UserAccountingService {
- /**
- * The default simulation budget for new users.
- */
- private final Duration simulationBudget;
-
- /**
- * Construct a {@link UserAccountingService} instance.
- *
- * @param simulationBudget The default simulation budget for new users.
- */
- public UserAccountingService(
- @ConfigProperty(name = "opendc.accounting.simulation-budget", defaultValue = "2000m")
- Duration simulationBudget) {
- this.simulationBudget = simulationBudget;
- }
-
- /**
- * Return the {@link org.opendc.web.proto.user.UserAccounting} object for the user with the
- * specified <code>userId</code>. If the object does not exist in the database, a default value is constructed.
- */
- public org.opendc.web.proto.user.UserAccounting getAccounting(String userId) {
- UserAccounting accounting = UserAccounting.findByUser(userId);
- if (accounting != null) {
- return new org.opendc.web.proto.user.UserAccounting(
- accounting.periodEnd, accounting.simulationTime, accounting.simulationTimeBudget);
- }
-
- return new org.opendc.web.proto.user.UserAccounting(
- getNextAccountingPeriod(LocalDate.now()), 0, (int) simulationBudget.toSeconds());
- }
-
- /**
- * Determine whether the user with <code>userId</code> has any remaining simulation budget.
- *
- * @param userId The unique identifier of the user.
- * @return <code>true</code> when the user still has budget left, <code>false</code> otherwise.
- */
- public boolean hasSimulationBudget(String userId) {
- UserAccounting accounting = UserAccounting.findByUser(userId);
- if (accounting == null) {
- return true;
- }
- return accounting.hasSimulationBudget();
- }
-
- /**
- * Consume <code>seconds</code> from the simulation budget of the user with <code>userId</code>.
- *
- * @param userId The unique identifier of the user.
- * @param seconds The seconds to consume from the simulation budget.
- * @return <code>true</code> if the user has consumed his full budget or <code>false</code> if there is still budget
- * remaining.
- */
- public boolean consumeSimulationBudget(String userId, int seconds) {
- LocalDate today = LocalDate.now();
- LocalDate nextAccountingPeriod = getNextAccountingPeriod(today);
-
- // We need to be careful to prevent conflicts in case of concurrency
- // 1. First, we try to create the accounting object if it does not exist yet. This may fail if another instance
- // creates the object concurrently.
- // 2. Second, we check if the budget needs to be reset and try this atomically.
- // 3. Finally, we atomically consume the budget from the object
- // This is repeated three times in case there is a conflict
- for (int i = 0; i < 3; i++) {
- UserAccounting accounting = UserAccounting.findByUser(userId);
-
- if (accounting == null) {
- try {
- UserAccounting newAccounting = UserAccounting.create(
- userId, nextAccountingPeriod, (int) simulationBudget.toSeconds(), seconds);
- return !newAccounting.hasSimulationBudget();
- } catch (EntityExistsException e) {
- // Conflict due to concurrency; retry
- }
- } else {
- boolean success;
-
- if (!today.isBefore(accounting.periodEnd)) {
- success = accounting.resetBudget(nextAccountingPeriod, seconds);
- } else {
- success = accounting.consumeBudget(seconds);
- }
-
- if (success) {
- return !accounting.hasSimulationBudget();
- }
- }
- }
-
- throw new IllegalStateException("Failed to allocate consume budget due to conflict");
- }
-
- /**
- * Helper method to find next accounting period.
- */
- private static LocalDate getNextAccountingPeriod(LocalDate today) {
- return today.with(TemporalAdjusters.firstDayOfNextMonth());
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java
deleted file mode 100644
index 103f868d..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/DevSecurityOverrideFilter.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util;
-
-import io.quarkus.arc.properties.IfBuildProperty;
-import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.container.ContainerRequestFilter;
-import jakarta.ws.rs.container.PreMatching;
-import jakarta.ws.rs.core.SecurityContext;
-import jakarta.ws.rs.ext.Provider;
-import java.security.Principal;
-
-/**
- * Helper class to disable security for the OpenDC web API when in development mode.
- */
-@Provider
-@PreMatching
-@IfBuildProperty(name = "opendc.security.enabled", stringValue = "false")
-public class DevSecurityOverrideFilter implements ContainerRequestFilter {
- @Override
- public void filter(ContainerRequestContext requestContext) {
- requestContext.setSecurityContext(new SecurityContext() {
- @Override
- public Principal getUserPrincipal() {
- return () -> "anon";
- }
-
- @Override
- public boolean isUserInRole(String role) {
- return true;
- }
-
- @Override
- public boolean isSecure() {
- return false;
- }
-
- @Override
- public String getAuthenticationScheme() {
- return "basic";
- }
- });
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java
deleted file mode 100644
index ff3ba1cd..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/KotlinModuleCustomizer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.module.kotlin.KotlinModule;
-import io.quarkus.jackson.ObjectMapperCustomizer;
-import jakarta.inject.Singleton;
-
-/**
- * Helper class to register the Kotlin Jackson module.
- */
-@Singleton
-public final class KotlinModuleCustomizer implements ObjectMapperCustomizer {
- @Override
- public void customize(ObjectMapper objectMapper) {
- objectMapper.registerModule(new KotlinModule.Builder().build());
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java
deleted file mode 100644
index 60ca77e5..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/QuarkusObjectMapperSupplier.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import io.hypersistence.utils.hibernate.type.util.ObjectMapperSupplier;
-import io.quarkus.runtime.annotations.RegisterForReflection;
-import jakarta.enterprise.inject.spi.CDI;
-
-/**
- * A supplier for an {@link ObjectMapper} used by the Hypersistence utilities.
- */
-@RegisterForReflection
-public class QuarkusObjectMapperSupplier implements ObjectMapperSupplier {
- @Override
- public ObjectMapper get() {
- return CDI.current().select(ObjectMapper.class).get();
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java b/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java
deleted file mode 100644
index 47d397f3..00000000
--- a/opendc-web/opendc-web-server/src/main/java/org/opendc/web/server/util/runner/QuarkusJobManager.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.util.runner;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.transaction.Transactional;
-import java.util.Map;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.runner.JobManager;
-import org.opendc.web.server.model.Job;
-import org.opendc.web.server.rest.runner.RunnerProtocol;
-import org.opendc.web.server.service.JobService;
-
-/**
- * Implementation of {@link JobManager} that interfaces directly with the database without overhead of the REST API.
- */
-@ApplicationScoped
-public class QuarkusJobManager implements JobManager {
- /**
- * The {@link JobService} used to manage the job's lifecycle.
- */
- private final JobService jobService;
-
- /**
- * Construct a {@link QuarkusJobManager}.
- *
- * @param jobService The {@link JobService} for managing the job's lifecycle.
- */
- public QuarkusJobManager(JobService jobService) {
- this.jobService = jobService;
- }
-
- @Transactional
- @Nullable
- @Override
- public org.opendc.web.proto.runner.Job findNext() {
- var job = Job.findByState(JobState.PENDING).firstResult();
- if (job == null) {
- return null;
- }
-
- return RunnerProtocol.toDto(job);
- }
-
- @Transactional
- @Override
- public boolean claim(long id) {
- return updateState(id, JobState.CLAIMED, 0, null);
- }
-
- @Transactional
- @Override
- public boolean heartbeat(long id, int runtime) {
- return updateState(id, JobState.RUNNING, runtime, null);
- }
-
- @Transactional
- @Override
- public void fail(long id, int runtime) {
- updateState(id, JobState.FAILED, runtime, null);
- }
-
- @Transactional
- @Override
- public void finish(long id, int runtime, @NotNull Map<String, ?> results) {
- updateState(id, JobState.FINISHED, runtime, results);
- }
-
- /**
- * Helper method to update the state of a job.
- *
- * @param id The unique id of the job.
- * @param newState The new state to transition to.
- * @param runtime The runtime of the job.
- * @param results The results of the job.
- * @return <code>true</code> if the operation succeeded, <code>false</code> otherwise.
- */
- private boolean updateState(long id, JobState newState, int runtime, Map<String, ?> results) {
- Job job = Job.findById(id);
-
- if (job == null) {
- return false;
- }
-
- try {
- jobService.updateJob(job, newState, runtime, results);
- return true;
- } catch (IllegalArgumentException | IllegalStateException e) {
- return false;
- }
- }
-}
diff --git a/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png b/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png
deleted file mode 100644
index d743038b..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/META-INF/branding/logo.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-dev.properties b/opendc-web/opendc-web-server/src/main/resources/application-dev.properties
deleted file mode 100644
index 5fbc4c04..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-dev.properties
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Datasource (H2)
-quarkus.datasource.db-kind=h2
-quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json;
-
-# Hibernate
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
-quarkus.flyway.clean-at-start=true
-
-# Disable authentication
-opendc.security.enabled=false
-
-# Mount web UI at root and API at "/api"
-quarkus.resteasy.path=/api
-
-# Swagger UI
-quarkus.smallrye-openapi.servers=http://localhost:8080
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-docker.properties b/opendc-web/opendc-web-server/src/main/resources/application-docker.properties
deleted file mode 100644
index eae9ee1e..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-docker.properties
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Configuration for standalone Docker server distribution without web UI.
-
-# Datasource
-quarkus.datasource.db-kind=postgresql
-quarkus.datasource.username=${OPENDC_DB_USERNAME}
-quarkus.datasource.password=${OPENDC_DB_PASSWORD}
-quarkus.datasource.jdbc.url=${OPENDC_DB_URL}
-
-# Hibernate
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL95Dialect
-
-# Disable OpenDC web UI
-quarkus.opendc-ui.include=false
-
-# Security
-opendc.security.enabled=true
-quarkus.oidc.auth-server-url=https://${OPENDC_AUTH0_DOMAIN}
-quarkus.oidc.client-id=${OPENDC_AUTH0_AUDIENCE}
-quarkus.oidc.token.audience=${quarkus.oidc.client-id}
-quarkus.oidc.roles.role-claim-path=scope
-
-# Swagger UI
-quarkus.swagger-ui.oauth-client-id=${OPENDC_AUTH0_DOCS_CLIENT_ID:}
-quarkus.swagger-ui.oauth-additional-query-string-params={"audience":"${OPENDC_AUTH0_AUDIENCE:https://api.opendc.org/v2/}"}
-
-quarkus.smallrye-openapi.security-scheme=oidc
-quarkus.smallrye-openapi.security-scheme-name=Auth0
-quarkus.smallrye-openapi.oidc-open-id-connect-url=https://${OPENDC_AUTH0_DOMAIN:opendc.eu.auth0.com}/.well-known/openid-configuration
-quarkus.smallrye-openapi.servers=https://api.opendc.org
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-prod.properties b/opendc-web/opendc-web-server/src/main/resources/application-prod.properties
deleted file mode 100644
index fe997fc0..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-prod.properties
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Datasource (H2)
-quarkus.datasource.db-kind=h2
-quarkus.datasource.jdbc.url=jdbc:h2:file:./data/opendc;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json;
-
-# Hibernate
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
-
-# Disable authentication
-opendc.security.enabled=false
-quarkus.oidc.enabled=${opendc.security.enabled}
-
-# Mount web UI at root and API at "/api"
-quarkus.resteasy.path=/api
-
-# Swagger UI
-quarkus.smallrye-openapi.servers=http://localhost:8080
diff --git a/opendc-web/opendc-web-server/src/main/resources/application-test.properties b/opendc-web/opendc-web-server/src/main/resources/application-test.properties
deleted file mode 100644
index 4e3063e4..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application-test.properties
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Datasource configuration
-quarkus.datasource.db-kind = h2
-quarkus.datasource.jdbc.url=jdbc:h2:mem:default;DB_CLOSE_DELAY=-1;INIT=CREATE TYPE IF NOT EXISTS "JSONB" AS json;
-
-quarkus.hibernate-orm.dialect=org.hibernate.dialect.H2Dialect
-quarkus.hibernate-orm.log.sql=true
-quarkus.flyway.clean-at-start=true
-quarkus.flyway.locations=db/migration,db/testing
-
-# Disable security
-quarkus.oidc.enabled=false
-
-# Disable OpenAPI/Swagger
-quarkus.smallrye-openapi.enable=false
-quarkus.swagger-ui.enable=false
-
-# Disable OpenDC web UI and runner
-quarkus.opendc-ui.include=false
-quarkus.opendc-runner.include=false
-
-# Create new tables and fill them
-quarkus.hibernate-orm.database.generation=drop-and-create
-quarkus.hibernate-orm.sql-load-script=load_data.sql
diff --git a/opendc-web/opendc-web-server/src/main/resources/application.properties b/opendc-web/opendc-web-server/src/main/resources/application.properties
deleted file mode 100644
index 0f47db30..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/application.properties
+++ /dev/null
@@ -1,49 +0,0 @@
-# Copyright (c) 2022 AtLarge Research
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in all
-# copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-# Enable CORS
-quarkus.http.cors=true
-quarkus.http.cors.origins=http://localhost:3000,https://opendc.org
-
-# Security
-quarkus.oidc.enabled=${opendc.security.enabled}
-
-# Runner logging
-quarkus.log.category."org.opendc".level=ERROR
-quarkus.log.category."org.opendc.web".level=INFO
-quarkus.log.category."org.apache".level=WARN
-
-# OpenAPI and Swagger
-quarkus.smallrye-openapi.info-title=OpenDC REST API
-%dev.quarkus.smallrye-openapi.info-title=OpenDC REST API (development)
-quarkus.smallrye-openapi.info-version=2.1-rc1
-quarkus.smallrye-openapi.info-description=OpenDC is an open-source datacenter simulator for education, featuring real-time online collaboration, diverse simulation models, and detailed performance feedback statistics.
-quarkus.smallrye-openapi.info-contact-email=opendc@atlarge-research.com
-quarkus.smallrye-openapi.info-contact-name=OpenDC Support
-quarkus.smallrye-openapi.info-contact-url=https://opendc.org
-quarkus.smallrye-openapi.info-license-name=MIT
-quarkus.smallrye-openapi.info-license-url=https://github.com/atlarge-research/opendc/blob/master/LICENSE.txt
-
-quarkus.swagger-ui.path=docs
-quarkus.swagger-ui.always-include=true
-
-# Flyway database migrations
-quarkus.flyway.baseline-on-migrate=true
-quarkus.flyway.migrate-at-start=true
diff --git a/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties b/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties
deleted file mode 100644
index 451ce2d8..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/hypersistence-utils.properties
+++ /dev/null
@@ -1 +0,0 @@
-hypersistence.utils.jackson.object.mapper=org.opendc.web.server.util.QuarkusObjectMapperSupplier
diff --git a/opendc-web/opendc-web-server/src/main/resources/load_data.sql b/opendc-web/opendc-web-server/src/main/resources/load_data.sql
deleted file mode 100644
index 72396cef..00000000
--- a/opendc-web/opendc-web-server/src/main/resources/load_data.sql
+++ /dev/null
@@ -1,124 +0,0 @@
-
--- Insert data
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
- VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 1', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 1);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 1, 'test_user_1');
-
--- Add test user 2 as a viewer for project 1
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('VIEWER', 1, 'test_user_2');
-
--- Add test user 3 as an editor for project 1
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('EDITOR', 1, 'test_user_3');
-
--- Create a project for test user 2
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 2', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 2);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 2, 'test_user_2');
-
--- Create three projects for test user 3. User 3 has multiple projects to test getAll
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 3', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 3);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 3, 'test_user_3');
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 4', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 4);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 4, 'test_user_3');
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project 5', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 5);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 5, 'test_user_3');
-
--- Project to delete
-
-INSERT INTO PROJECT (created_at, name, portfolios_created, scenarios_created, topologies_created, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Project Delete', 0, 0, 0, '2024-03-01T15:31:41.579969Z', 6);
-
-INSERT INTO PROJECTAUTHORIZATION (role, project_id, user_name)
-VALUES ('OWNER', 6, 'test_user_1');
-
--- --------------------------------------------------------------------------------
--- PortFolios
--- --------------------------------------------------------------------------------
-
--- Add Portfolio to project 1
-INSERT INTO PORTFOLIO (name, number, project_id, targets, id)
-VALUES ('Test PortFolio Base', 1, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 1);
-
-INSERT INTO PORTFOLIO (name, number, project_id, targets, id)
-VALUES ('Test PortFolio Delete', 2, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 2);
-
-INSERT INTO PORTFOLIO (name, number, project_id, targets, id)
-VALUES ('Test PortFolio DeleteEditor', 3, 1, '{"metrics": [], "repeats":1}' FORMAT JSON, 3);
-
-UPDATE Project p
-SET p.portfolios_created = 3, p.updated_at = '2024-03-01T15:31:41.579969Z'
-WHERE p.id = 1;
-
--- --------------------------------------------------------------------------------
--- Topologies
--- --------------------------------------------------------------------------------
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testUpdate', 1, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 1);
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDeleteAsEditor', 2, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 2);
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDelete', 3, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 3);
-
-INSERT INTO TOPOLOGY (created_at, name, number, project_id, rooms, updated_at, id)
-VALUES ('2024-03-01T15:31:41.579969Z', 'Test Topology testDeleteUsed', 4, 1, '[]' FORMAT JSON, '2024-03-01T15:31:41.579969Z', 4);
-
-UPDATE Project p
-SET p.topologies_created = 4, p.updated_at = '2024-03-01T15:31:41.579969Z'
-WHERE p.id = 1;
-
--- --------------------------------------------------------------------------------
--- Traces
--- --------------------------------------------------------------------------------
-
-INSERT INTO TRACE (id, name, type)
-VALUES ('bitbrains-small', 'Bitbrains Small', 'small');
-
--- --------------------------------------------------------------------------------
--- Scenario
--- --------------------------------------------------------------------------------
-
-INSERT INTO SCENARIO (name, number, phenomena, portfolio_id, project_id, scheduler_name, topology_id, sampling_fraction, trace_id, id)
-VALUES ('Test Scenario testDelete', 1, '{"failures": false, "interference": false}' FORMAT JSON, 1, 1, 'test', 1, 1.0, 'bitbrains-small', 1);
-
-INSERT INTO SCENARIO (name, number, phenomena, portfolio_id, project_id, scheduler_name, topology_id, sampling_fraction, trace_id, id)
-VALUES ('Test Scenario testDeleteUsed', 2, '{"failures": false, "interference": false}' FORMAT JSON, 1, 1, 'test', 4, 1.0, 'bitbrains-small', 2);
-
-
-UPDATE Project p
-SET p.scenarios_created = 2, p.updated_at = '2024-03-01T15:31:41.579969Z'
-WHERE p.id = 1;
-
--- --------------------------------------------------------------------------------
--- Job
--- --------------------------------------------------------------------------------
-
-INSERT INTO JOB (scenario_id, created_by, created_at, repeats, updated_at, state, runtime, results, id)
-VALUES (1, 'test_user_1', '2024-03-01T15:31:41.579969Z', 1, '2024-03-01T15:31:41.579969Z', 'PENDING', 1, '{}' FORMAT JSON, 1);
-
-INSERT INTO JOB (scenario_id, created_by, created_at, repeats, updated_at, state, runtime, results, id)
-VALUES (1, 'test_user_1', '2024-03-01T15:31:41.579969Z', 1, '2024-03-01T15:31:41.579969Z', 'PENDING', 1, '{}' FORMAT JSON, 2);
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/SchedulerResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/SchedulerResourceTest.java
deleted file mode 100644
index f52ede3a..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/SchedulerResourceTest.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import static io.restassured.RestAssured.given;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test suite for {@link SchedulerResource}.
- */
-@QuarkusTest
-@TestHTTPEndpoint(SchedulerResource.class)
-public final class SchedulerResourceTest {
- /**
- * Test to verify whether we can obtain all schedulers.
- */
- @Test
- public void testGetSchedulers() {
- given().get().then().statusCode(200);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/TraceResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/TraceResourceTest.java
deleted file mode 100644
index 9da26059..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/TraceResourceTest.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest;
-
-import static io.restassured.RestAssured.when;
-import static org.hamcrest.Matchers.equalTo;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.restassured.http.ContentType;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test suite for {@link TraceResource}.
- */
-@QuarkusTest
-@TestHTTPEndpoint(TraceResource.class)
-public final class TraceResourceTest {
- /**
- * Test that tries to obtain all traces.
- */
- @Test
- public void testGetAllEmpty() {
- when().get().then().statusCode(200);
- }
-
- /**
- * Test that tries to obtain a non-existent trace.
- */
- @Test
- public void testGetNonExisting() {
- when().get("/unknown").then().statusCode(404);
- }
-
- /**
- * Test that tries to obtain an existing trace.
- */
- @Test
- public void testGetExisting() {
- when().get("/bitbrains-small")
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("name", equalTo("Bitbrains Small"));
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/runner/JobResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/runner/JobResourceTest.java
deleted file mode 100644
index 09f60c0a..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/runner/JobResourceTest.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.runner;
-
-import static io.restassured.RestAssured.given;
-import static org.hamcrest.Matchers.equalTo;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.security.TestSecurity;
-import io.restassured.http.ContentType;
-import org.junit.jupiter.api.Test;
-import org.opendc.web.proto.JobState;
-
-/**
- * Test suite for {@link JobResource}.
- */
-@QuarkusTest
-@TestHTTPEndpoint(JobResource.class)
-public final class JobResourceTest {
- /**
- * Test that tries to query the pending jobs without token.
- */
- @Test
- public void testQueryWithoutToken() {
- given().get().then().statusCode(401);
- }
-
- /**
- * Test that tries to query the pending jobs for a user.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testQueryInvalidScope() {
- given().get().then().statusCode(403);
- }
-
- /**
- * Test that tries to query the pending jobs for a runner.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testQuery() {
- given().get().then().statusCode(200).contentType(ContentType.JSON).body("get(0).state", equalTo("PENDING"));
- }
-
- /**
- * Test that tries to obtain a non-existent job.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testGetNonExisting() {
- given().get("/0").then().statusCode(404);
- }
-
- /**
- * Test that tries to obtain a job.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testGetExisting() {
- given().get("/1").then().statusCode(200).contentType(ContentType.JSON).body("id", equalTo(1));
- }
-
- /**
- * Test that tries to update a non-existent job.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testUpdateNonExistent() {
- given().body(new org.opendc.web.proto.runner.Job.Update(JobState.PENDING, 0, null))
- .contentType(ContentType.JSON)
- .when()
- .post("/0")
- .then()
- .statusCode(404)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to update a job.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testUpdateState() {
- given().body(new org.opendc.web.proto.runner.Job.Update(JobState.CLAIMED, 0, null))
- .contentType(ContentType.JSON)
- .when()
- .post("/2")
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("state", equalTo(JobState.CLAIMED.toString()));
- }
-
- /**
- * Test that tries to update a job with invalid input.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testUpdateInvalidInput() {
- given().body("{ \"test\": \"test\" }")
- .contentType(ContentType.JSON)
- .when()
- .post("/1")
- .then()
- .statusCode(400)
- .contentType(ContentType.JSON);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioResourceTest.java
deleted file mode 100644
index f23b4fc4..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioResourceTest.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import static io.restassured.RestAssured.given;
-import static org.hamcrest.Matchers.equalTo;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.security.TestSecurity;
-import io.restassured.http.ContentType;
-import java.util.Set;
-import org.junit.jupiter.api.Test;
-import org.opendc.web.proto.Targets;
-
-/**
- * Test suite for {@link PortfolioResource}.
- */
-@QuarkusTest
-@TestHTTPEndpoint(PortfolioResource.class)
-public final class PortfolioResourceTest {
- /**
- * Test that tries to obtain the list of all portfolios belonging to a project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetAllForProject() {
- given().pathParam("project", 1).when().get().then().statusCode(200);
- }
-
- /**
- * Test that tries to obtain the list of all portfolios belonging to a project
- * without authorization.
- *
- * TODO: Why is this an empty list, and not a 403 message?
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetAllForProjectNoAuthorization() {
- given().pathParam("project", 1).when().get().then().statusCode(200);
- }
-
- /**
- * Test that tries to create a portfolio for a project that exists and user has permission.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreate() {
- given().pathParam("project", "1")
- .body(new org.opendc.web.proto.user.Portfolio.Create("Test Portfolio New", new Targets(Set.of(), 1)))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("name", equalTo("Test Portfolio New"));
- }
-
- /**
- * Test that tries to create a topology for a project that does not exist.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateNonExistent() {
- given().pathParam("project", "0")
- .body(new org.opendc.web.proto.user.Portfolio.Create("test", new Targets(Set.of(), 1)))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(404);
- }
-
- /**
- * Test that tries to create a portfolio for a project that does exist but the user does not have permission.
- */
- @Test
- @TestSecurity(
- user = "test_user_2",
- roles = {"openid"})
- public void testCreateViewer() {
- given().pathParam("project", "1")
- .body(new org.opendc.web.proto.user.Portfolio.Create("test", new Targets(Set.of(), 1)))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(403);
- }
-
- /**
- * Test that tries to create a portfolio for a project that does exist but the user does not have permission.
- * TODO: This should return 403 but does not because there is no user class
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateNotPermitted() {
- given().pathParam("project", "3")
- .body(new org.opendc.web.proto.user.Portfolio.Create("test", new Targets(Set.of(), 1)))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(404);
- }
-
- /**
- * Test to create a portfolio with an empty body.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateEmpty() {
- given().pathParam("project", "1")
- .body("{}")
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400);
- }
-
- /**
- * Test to create a portfolio with a blank name.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateBlankName() {
- given().pathParam("project", "1")
- .body(new org.opendc.web.proto.user.Portfolio.Create("", new Targets(Set.of(), 1)))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400);
- }
-
- /**
- * Test that tries to obtain a portfolio without token.
- */
- @Test
- public void testGetWithoutToken() {
- given().pathParam("project", "1").when().get("/1").then().statusCode(401);
- }
-
- /**
- * Test that tries to obtain a portfolio with an invalid scope.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testGetInvalidToken() {
- given().pathParam("project", "1").when().get("/1").then().statusCode(403);
- }
-
- /**
- * Test that tries to obtain a non-existent portfolio.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetNonExisting() {
- given().pathParam("project", "1").when().get("/0").then().statusCode(404);
- }
-
- /**
- * Test that tries to obtain a portfolio for a non-existent project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetNonExistingProject() {
- given().pathParam("project", "0").when().get("/1").then().statusCode(404);
- }
-
- /**
- * Test that tries to obtain a portfolio.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetExisting() {
- given().pathParam("project", "1")
- .when()
- .get("/1")
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("id", equalTo(1));
- }
-
- /**
- * Test to delete a non-existent portfolio.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteNonExistent() {
- given().pathParam("project", "1").when().delete("/0").then().statusCode(404);
- }
-
- /**
- * Test to delete a portfolio on a non-existent project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteNonExistentProject() {
- given().pathParam("project", "0").when().delete("/1").then().statusCode(404);
- }
-
- /**
- * Test to delete a portfolio.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDelete() {
- given().pathParam("project", "1").when().delete("/2").then().statusCode(200);
- }
-
- /**
- * Test to delete a portfolio as an editor.
- */
- @Test
- @TestSecurity(
- user = "test_user_3",
- roles = {"openid"})
- public void testDeleteEditor() {
- given().pathParam("project", "1").when().delete("/3").then().statusCode(200);
- }
-
- /**
- * Test to delete a portfolio as a viewer.
- */
- @Test
- @TestSecurity(
- user = "test_user_2",
- roles = {"openid"})
- public void testDeleteAsViewer() {
- given().pathParam("project", "1").when().delete("/1").then().statusCode(403);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioScenarioResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioScenarioResourceTest.java
deleted file mode 100644
index 270dbae9..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/PortfolioScenarioResourceTest.java
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import static io.restassured.RestAssured.given;
-import static org.hamcrest.Matchers.equalTo;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.security.TestSecurity;
-import io.restassured.http.ContentType;
-import org.junit.jupiter.api.Test;
-import org.opendc.web.proto.OperationalPhenomena;
-import org.opendc.web.proto.Workload;
-import org.opendc.web.proto.user.Scenario;
-
-/**
- * Test suite for {@link PortfolioScenarioResource}.
- */
-@QuarkusTest
-@TestHTTPEndpoint(PortfolioScenarioResource.class)
-public final class PortfolioScenarioResourceTest {
- /**
- * Test that tries to obtain a portfolio without token.
- */
- @Test
- public void testGetWithoutToken() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .when()
- .get()
- .then()
- .statusCode(401);
- }
-
- /**
- * Test that tries to obtain a portfolio with an invalid scope.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testGetInvalidToken() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .when()
- .get()
- .then()
- .statusCode(403);
- }
-
- /**
- * Test that tries to obtain a scenario without authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetUnauthorized() {
- given().pathParam("project", "2")
- .pathParam("portfolio", "1")
- .when()
- .get()
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to obtain a scenario.
- * TODO: shouldn't this be all scenarios?
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGet() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .when()
- .get()
- .then()
- .statusCode(200);
- }
-
- /**
- * Test that tries to create a scenario for a portfolio that does not exist in a project that can be accessed.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateNonExistent() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "0")
- .body(new Scenario.Create(
- "test", new Workload.Spec("test", 1.0), 1, new OperationalPhenomena(false, false), "test"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(404)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to create a scenario for a portfolio without authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateUnauthorized() {
- given().pathParam("project", "2")
- .pathParam("portfolio", "1")
- .body(new Scenario.Create(
- "test", new Workload.Spec("test", 1.0), 1, new OperationalPhenomena(false, false), "test"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(404)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to create a scenario for a portfolio as a viewer.
- */
- @Test
- @TestSecurity(
- user = "test_user_2",
- roles = {"openid"})
- public void testCreateAsViewer() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .body(new Scenario.Create(
- "test", new Workload.Spec("test", 1.0), 1, new OperationalPhenomena(false, false), "test"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(403)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to create a scenario for a portfolio.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreate() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .body(new Scenario.Create(
- "Test Scenario New",
- new Workload.Spec("bitbrains-small", 1.0),
- 1,
- new OperationalPhenomena(false, false),
- "test"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("name", equalTo("Test Scenario New"));
- }
-
- /**
- * Test to create a project with an empty body.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateEmpty() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .body("{}")
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test to create a project with a blank name.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateBlankName() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .body(new Scenario.Create(
- "", new Workload.Spec("test", 1.0), 1, new OperationalPhenomena(false, false), "test"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to create a scenario for a portfolio with an unknown Topology.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateUnknownTopology() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .body(new Scenario.Create(
- "test",
- new Workload.Spec("bitbrains-small", 1.0),
- -1,
- new OperationalPhenomena(false, false),
- "test"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to create a scenario for a portfolio with an unknown Trace.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateUnknownTrace() {
- given().pathParam("project", "1")
- .pathParam("portfolio", "1")
- .body(new Scenario.Create(
- "test", new Workload.Spec("unknown", 1.0), 1, new OperationalPhenomena(false, false), "test"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400)
- .contentType(ContentType.JSON);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ProjectResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ProjectResourceTest.java
deleted file mode 100644
index 450c0c0c..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ProjectResourceTest.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import static io.restassured.RestAssured.given;
-import static io.restassured.RestAssured.when;
-import static org.hamcrest.Matchers.*;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.security.TestSecurity;
-import io.restassured.http.ContentType;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test suite for [ProjectResource].
- */
-@QuarkusTest
-@TestHTTPEndpoint(ProjectResource.class)
-public final class ProjectResourceTest {
- /**
- * Test that tries to obtain all projects without token.
- */
- @Test
- public void testGetAllWithoutToken() {
- when().get().then().statusCode(401);
- }
-
- /**
- * Test that tries to obtain all projects with an invalid scope.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testGetAllWithInvalidScope() {
- when().get().then().statusCode(403);
- }
-
- /**
- * Test that tries to obtain when no projects have yet been made.
- */
- @Test
- @TestSecurity(
- user = "test_user_4",
- roles = {"openid"})
- public void testGetAllWithNoAvailableProjects() {
- when().get().then().statusCode(200).contentType(ContentType.JSON).body("", empty());
- }
-
- /**
- * Test that tries to obtain all project for a user.
- */
- @Test
- @TestSecurity(
- user = "test_user_3",
- roles = {"openid"})
- public void testGetAll() {
- given().get().then().statusCode(200).contentType(ContentType.JSON).body("", hasSize(4));
- }
-
- /**
- * Test that tries to obtain a non-existent project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetNonExisting() {
- when().get("/0").then().statusCode(404).contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to obtain a project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetExisting() {
- // Try to get the project
- given().get("/1").then().statusCode(200).contentType(ContentType.JSON).body("id", equalTo(1));
- }
-
- /**
- * Test that tries to create a project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreate() {
- given().body(new org.opendc.web.proto.user.Project.Create("Test Project New"))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("name", equalTo("Test Project New"));
- }
-
- /**
- * Test to create a project with an empty body.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateEmpty() {
- given().body("{}").contentType(ContentType.JSON).when().post().then().statusCode(400);
- }
-
- /**
- * Test to create a project with a blank name.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateBlankName() {
- given().body(new org.opendc.web.proto.user.Project.Create(""))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400);
- }
-
- /**
- * Test to delete a project that is owned by the user.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDelete() {
- given().delete("/6").then().statusCode(200);
- }
-
- /**
- * Test to delete a non-existent project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteNonExistent() {
- when().delete("/0").then().statusCode(404);
- }
-
- /**
- * Test to delete a project which is not connected to the user.
- * test_user_3 is not connected to project 1.
- */
- @Test
- @TestSecurity(
- user = "test_user_3",
- roles = {"openid"})
- public void testDeleteNotConnected() {
- when().delete("/1").then().statusCode(403);
- }
-
- /**
- * Test to delete a project which the user does not own.
- * project 1 is owned by test_user_1, test_user_2 is a viewer
- * should not be able to delete it
- */
- @Test
- @TestSecurity(
- user = "test_user_2",
- roles = {"openid"})
- public void testDeleteNonOwner() {
- when().delete("/1").then().statusCode(403);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ScenarioResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ScenarioResourceTest.java
deleted file mode 100644
index d81f9655..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/ScenarioResourceTest.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import static io.restassured.RestAssured.given;
-import static org.hamcrest.Matchers.equalTo;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.security.TestSecurity;
-import io.restassured.http.ContentType;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test suite for {@link ScenarioResource}.
- */
-@QuarkusTest
-@TestHTTPEndpoint(ScenarioResource.class)
-public final class ScenarioResourceTest {
- /**
- * Test that tries to obtain all scenarios belonging to a project without authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetAllUnauthorized() {
- given().pathParam("project", "2").when().get().then().statusCode(404);
- }
-
- /**
- * Test that tries to obtain all scenarios belonging to a project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetAll() {
- given().pathParam("project", "1").when().get().then().statusCode(200);
- }
-
- /**
- * Test that tries to obtain a scenario without token.
- */
- @Test
- public void testGetWithoutToken() {
- given().pathParam("project", "1").when().get("/1").then().statusCode(401);
- }
-
- /**
- * Test that tries to obtain a scenario with an invalid scope.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testGetInvalidToken() {
- given().pathParam("project", "1").when().get("/1").then().statusCode(403);
- }
-
- /**
- * Test that tries to obtain a non-existent scenario.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetNonExisting() {
- given().pathParam("project", "1")
- .when()
- .get("/0")
- .then()
- .statusCode(404)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to obtain a scenario when it does not have authority to get to the project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetExistingUnauthorized() {
- given().pathParam("project", "2")
- .when()
- .get("/1")
- .then()
- .statusCode(404)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test that tries to obtain a scenario.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetExisting() {
- given().pathParam("project", "1")
- .when()
- .get("/1")
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("id", equalTo(1));
- }
-
- /**
- * Test to delete a non-existent scenario.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteNonExistent() {
- given().pathParam("project", "1").when().delete("/0").then().statusCode(404);
- }
-
- /**
- * Test to delete a scenario without authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteUnauthorized() {
- given().pathParam("project", "2").when().delete("/1").then().statusCode(404);
- }
-
- /**
- * Test to delete a scenario as a viewer.
- */
- @Test
- @TestSecurity(
- user = "test_user_2",
- roles = {"openid"})
- public void testDeleteAsViewer() {
- given().pathParam("project", "1").when().delete("/1").then().statusCode(403);
- }
-
- /**
- * Test to delete a scenario.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDelete() {
- given().pathParam("project", "1")
- .when()
- .delete("/1")
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/TopologyResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/TopologyResourceTest.java
deleted file mode 100644
index 277376e5..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/TopologyResourceTest.java
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import static io.restassured.RestAssured.given;
-import static org.hamcrest.Matchers.equalTo;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.security.TestSecurity;
-import io.restassured.http.ContentType;
-import java.util.List;
-import org.junit.jupiter.api.Test;
-import org.opendc.web.proto.user.Topology;
-
-/**
- * Test suite for {@link TopologyResource}.
- */
-@QuarkusTest
-@TestHTTPEndpoint(TopologyResource.class)
-public final class TopologyResourceTest {
- /**
- * Test that tries to obtain the list of topologies of a project without proper authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_4",
- roles = {"openid"})
- public void testGetAllWithoutAuth() {
- given().pathParam("project", "1")
- .when()
- .get()
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body(equalTo("[]"));
- }
-
- /**
- * Test that tries to obtain the list of topologies belonging to a project.
- * TODO: check if any topology comes back
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetAll() {
- given().pathParam("project", "1").when().get().then().statusCode(200);
- }
-
- /**
- * Test that tries to create a topology for a project that does not exist.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateNonExistent() {
- given().pathParam("project", "0")
- .body(new Topology.Create("test", List.of()))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(404);
- }
-
- /**
- * Test that tries to create a topology for a project while not authorized.
- * TODO: should probably return 403, but this does not work in the current system
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateUnauthorized() {
- given().pathParam("project", "2")
- .body(new Topology.Create("test", List.of()))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(404);
- }
-
- /**
- * Test that tries to create a topology for a project.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreate() {
- given().pathParam("project", "1")
- .body(new Topology.Create("Test Topology New", List.of()))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("name", equalTo("Test Topology New"));
- }
-
- /**
- * Test to create a topology with an empty body.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateEmpty() {
- given().pathParam("project", "1")
- .body("{}")
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400);
- }
-
- /**
- * Test to create a topology with a blank name.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testCreateBlankName() {
- given().pathParam("project", "1")
- .body(new Topology.Create("", List.of()))
- .contentType(ContentType.JSON)
- .when()
- .post()
- .then()
- .statusCode(400);
- }
-
- /**
- * Test that tries to obtain a topology without token.
- */
- @Test
- public void testGetWithoutToken() {
- given().pathParam("project", "1").when().get("/1").then().statusCode(401);
- }
-
- /**
- * Test that tries to obtain a topology with an invalid scope.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"runner"})
- public void testGetInvalidToken() {
- given().pathParam("project", "1").when().get("/1").then().statusCode(403);
- }
-
- /**
- * Test that tries to obtain a non-existent topology.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetNonExisting() {
- given().pathParam("project", "1").when().get("/0").then().statusCode(404);
- }
-
- /**
- * Test that tries to obtain a topology without authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetUnauthorized() {
- given().pathParam("project", "2").when().get("/1").then().statusCode(404);
- }
-
- /**
- * Test that tries to obtain a topology.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testGetExisting() {
- given().pathParam("project", "1")
- .when()
- .get("/1")
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("id", equalTo(1));
- }
-
- /**
- * Test to delete a non-existent topology.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testUpdateNonExistent() {
- given().pathParam("project", "1")
- .body(new Topology.Update(List.of()))
- .contentType(ContentType.JSON)
- .when()
- .put("/0")
- .then()
- .statusCode(404);
- }
-
- /**
- * Test to delete a topology without authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testUpdateUnauthorized() {
- given().pathParam("project", "2")
- .body(new Topology.Update(List.of()))
- .contentType(ContentType.JSON)
- .when()
- .put("/1")
- .then()
- .statusCode(404);
- }
-
- /**
- * Test to update a topology as a viewer.
- * TODO: should return 403, but currently returns 404
- */
- @Test
- @TestSecurity(
- user = "test_user_2",
- roles = {"openid"})
- public void testUpdateAsViewer() {
- given().pathParam("project", "1")
- .body(new Topology.Update(List.of()))
- .contentType(ContentType.JSON)
- .when()
- .put("/1")
- .then()
- .statusCode(403)
- .contentType(ContentType.JSON);
- }
-
- /**
- * Test to update a topology.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testUpdate() {
- given().pathParam("project", "1")
- .body(new Topology.Update(List.of()))
- .contentType(ContentType.JSON)
- .when()
- .put("/1")
- .then()
- .statusCode(200);
- }
-
- /**
- * Test to delete a non-existent topology.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteNonExistent() {
- given().pathParam("project", "1").when().delete("/0").then().statusCode(404);
- }
-
- /**
- * Test to delete a topology without authorization.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteUnauthorized() {
- given().pathParam("project", "2").when().delete("/1").then().statusCode(404);
- }
-
- /**
- * Test to delete a topology as a viewer.
- */
- @Test
- @TestSecurity(
- user = "test_user_2",
- roles = {"openid"})
- public void testDeleteAsViewer() {
- given().pathParam("project", "1").when().delete("/1").then().statusCode(403);
- }
-
- /**
- * Test to delete a topology as a viewer.
- */
- @Test
- @TestSecurity(
- user = "test_user_3",
- roles = {"openid"})
- public void testDeleteAsEditor() {
- given().pathParam("project", "1").when().delete("/2").then().statusCode(200);
- }
-
- /**
- * Test to delete a topology.
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDelete() {
- given().pathParam("project", "1").when().delete("/3").then().statusCode(200);
- }
-
- /**
- * Test to delete a topology that is still being used by a scenario.
- * TODO: fix later
- */
- @Test
- @TestSecurity(
- user = "test_user_1",
- roles = {"openid"})
- public void testDeleteUsed() {
- given().pathParam("project", "1")
- .when()
- .delete("/4") // Topology 1 is still used by scenario 1 and 2
- .then()
- .statusCode(403)
- .contentType(ContentType.JSON);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/UserResourceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/UserResourceTest.java
deleted file mode 100644
index 6dcb3b4d..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/rest/user/UserResourceTest.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.rest.user;
-
-import static io.restassured.RestAssured.when;
-import static org.hamcrest.Matchers.equalTo;
-import static org.hamcrest.Matchers.greaterThan;
-
-import io.quarkus.test.common.http.TestHTTPEndpoint;
-import io.quarkus.test.junit.QuarkusTest;
-import io.quarkus.test.security.TestSecurity;
-import io.restassured.http.ContentType;
-import org.junit.jupiter.api.Test;
-
-/**
- * Test suite for [UserResource].
- */
-@QuarkusTest
-@TestHTTPEndpoint(UserResource.class)
-public final class UserResourceTest {
- /**
- * Test that tries to obtain the profile of the active user.
- */
- @Test
- @TestSecurity(
- user = "testUser",
- roles = {"openid"})
- public void testMe() {
- when().get("me")
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .body("userId", equalTo("testUser"))
- .body("accounting.simulationTime", equalTo(0))
- .body("accounting.simulationTimeBudget", greaterThan(0));
- }
-
- /**
- * Test that tries to obtain the profile of the active user without authorization.
- */
- @Test
- public void testMeUnauthorized() {
- when().get("me").then().statusCode(401);
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/JobServiceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/JobServiceTest.java
deleted file mode 100644
index f6d871c0..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/JobServiceTest.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.service;
-
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
-
-import io.quarkus.test.junit.QuarkusTest;
-import java.time.Instant;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-import org.opendc.web.proto.JobState;
-import org.opendc.web.server.model.Job;
-
-/**
- * Test suite for the {@link JobService}.
- */
-@QuarkusTest
-public class JobServiceTest {
- /**
- * The {@link JobService} instance under test.
- */
- private JobService service;
-
- /**
- * The mock {@link UserAccountingService}.
- */
- private UserAccountingService mockAccountingService;
-
- @BeforeEach
- public void setUp() {
- mockAccountingService = Mockito.mock(UserAccountingService.class);
- service = new JobService(mockAccountingService);
- }
-
- @Test
- public void testUpdateInvalidTransition() {
- Job job = new Job(null, "test", Instant.now(), 1);
- job.state = JobState.RUNNING;
-
- assertThrows(IllegalArgumentException.class, () -> service.updateJob(job, JobState.CLAIMED, 0, null));
-
- Mockito.verifyNoInteractions(mockAccountingService);
- }
-
- @Test
- public void testUpdateNoBudget() {
- Job job = Mockito.spy(new Job(null, "test", Instant.now(), 1));
- job.state = JobState.RUNNING;
-
- Mockito.when(mockAccountingService.consumeSimulationBudget(any(), anyInt()))
- .thenReturn(true);
- Mockito.doReturn(true).when(job).updateAtomically(any(), any(), anyInt(), any());
-
- service.updateJob(job, JobState.RUNNING, 0, null);
-
- Mockito.verify(job).updateAtomically(eq(JobState.FAILED), any(), anyInt(), any());
- }
-
- @Test
- public void testUpdateNoBudgetWhenFinishing() {
- Job job = Mockito.spy(new Job(null, "test", Instant.now(), 1));
- job.state = JobState.RUNNING;
-
- Mockito.when(mockAccountingService.consumeSimulationBudget(any(), anyInt()))
- .thenReturn(true);
- Mockito.doReturn(true).when(job).updateAtomically(any(), any(), anyInt(), any());
-
- service.updateJob(job, JobState.FINISHED, 0, null);
-
- Mockito.verify(job).updateAtomically(eq(JobState.FINISHED), any(), anyInt(), any());
- }
-
- @Test
- public void testUpdateSuccess() {
- Job job = Mockito.spy(new Job(null, "test", Instant.now(), 1));
- job.state = JobState.RUNNING;
-
- Mockito.when(mockAccountingService.consumeSimulationBudget(any(), anyInt()))
- .thenReturn(false);
- Mockito.doReturn(true).when(job).updateAtomically(any(), any(), anyInt(), any());
-
- service.updateJob(job, JobState.FINISHED, 0, null);
-
- Mockito.verify(job).updateAtomically(eq(JobState.FINISHED), any(), anyInt(), any());
- }
-
- @Test
- public void testUpdateConflict() {
- Job job = Mockito.spy(new Job(null, "test", Instant.now(), 1));
- job.state = JobState.RUNNING;
-
- Mockito.when(mockAccountingService.consumeSimulationBudget(any(), anyInt()))
- .thenReturn(false);
- Mockito.doReturn(false).when(job).updateAtomically(any(), any(), anyInt(), any());
-
- assertThrows(IllegalStateException.class, () -> service.updateJob(job, JobState.FINISHED, 0, null));
-
- Mockito.verify(job).updateAtomically(eq(JobState.FINISHED), any(), anyInt(), any());
- }
-}
diff --git a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/UserAccountingServiceTest.java b/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/UserAccountingServiceTest.java
deleted file mode 100644
index 91e3eb66..00000000
--- a/opendc-web/opendc-web-server/src/test/java/org/opendc/web/server/service/UserAccountingServiceTest.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (c) 2023 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.server.service;
-
-import static org.junit.jupiter.api.Assertions.assertAll;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-
-import io.quarkus.panache.mock.PanacheMock;
-import io.quarkus.test.junit.QuarkusTest;
-import jakarta.persistence.EntityExistsException;
-import java.time.Duration;
-import java.time.LocalDate;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
-import org.opendc.web.server.model.UserAccounting;
-
-/**
- * Test suite for the {@link UserAccountingService}.
- */
-@QuarkusTest
-public class UserAccountingServiceTest {
- /**
- * The {@link UserAccountingService} instance under test.
- */
- private UserAccountingService service;
-
- /**
- * The user id to test with
- */
- private final String userId = "test";
-
- @BeforeEach
- public void setUp() {
- PanacheMock.mock(UserAccounting.class);
- service = new UserAccountingService(Duration.ofHours(1));
- }
-
- @Test
- public void testGetUserDoesNotExist() {
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(null);
-
- var accounting = service.getAccounting(userId);
-
- assertTrue(accounting.getPeriodEnd().isAfter(LocalDate.now()));
- assertEquals(0, accounting.getSimulationTime());
- }
-
- @Test
- public void testGetUserDoesExist() {
- var now = LocalDate.now();
- var periodEnd = now.plusMonths(1);
-
- var mockAccounting = new UserAccounting(userId, periodEnd, 3600);
- mockAccounting.simulationTime = 32;
-
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(mockAccounting);
-
- var accounting = service.getAccounting(userId);
-
- assertAll(
- () -> assertEquals(periodEnd, accounting.getPeriodEnd()),
- () -> assertEquals(32, accounting.getSimulationTime()),
- () -> assertEquals(3600, accounting.getSimulationTimeBudget()));
- }
-
- @Test
- public void testHasBudgetUserDoesNotExist() {
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(null);
-
- assertTrue(service.hasSimulationBudget(userId));
- }
-
- @Test
- public void testHasBudget() {
- var periodEnd = LocalDate.now().plusMonths(2);
-
- var mockAccounting = new UserAccounting(userId, periodEnd, 3600);
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(mockAccounting);
-
- assertTrue(service.hasSimulationBudget(userId));
- }
-
- @Test
- public void testHasBudgetExceededButPeriodExpired() {
- var periodEnd = LocalDate.now().minusMonths(2);
-
- var mockAccounting = new UserAccounting(userId, periodEnd, 3600);
- mockAccounting.simulationTime = 3900;
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(mockAccounting);
-
- assertTrue(service.hasSimulationBudget(userId));
- }
-
- @Test
- public void testHasBudgetPeriodExpired() {
- var periodEnd = LocalDate.now().minusMonths(2);
-
- var mockAccounting = new UserAccounting(userId, periodEnd, 3600);
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(mockAccounting);
-
- assertTrue(service.hasSimulationBudget(userId));
- }
-
- @Test
- public void testHasBudgetExceeded() {
- var periodEnd = LocalDate.now().plusMonths(1);
-
- var mockAccounting = new UserAccounting(userId, periodEnd, 3600);
- mockAccounting.simulationTime = 3900;
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(mockAccounting);
-
- assertFalse(service.hasSimulationBudget(userId));
- }
-
- @Test
- public void testConsumeBudgetNewUser() {
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(null);
- Mockito.when(UserAccounting.create(anyString(), any(), anyInt(), anyInt()))
- .thenAnswer((i) -> {
- var accounting = new UserAccounting(i.getArgument(0), i.getArgument(1), i.getArgument(2));
- accounting.simulationTime = i.getArgument(3);
- return accounting;
- });
-
- assertFalse(service.consumeSimulationBudget(userId, 10));
- }
-
- @Test
- public void testConsumeBudgetNewUserExceeded() {
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(null);
- Mockito.when(UserAccounting.create(anyString(), any(), anyInt(), anyInt()))
- .thenAnswer((i) -> {
- var accounting = new UserAccounting(i.getArgument(0), i.getArgument(1), i.getArgument(2));
- accounting.simulationTime = i.getArgument(3);
- return accounting;
- });
-
- assertTrue(service.consumeSimulationBudget(userId, 4000));
- }
-
- @Test
- public void testConsumeBudgetNewUserConflict() {
- var periodEnd = LocalDate.now().plusMonths(1);
- var accountingMock = Mockito.spy(new UserAccounting(userId, periodEnd, 3600));
-
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(null).thenReturn(accountingMock);
- Mockito.when(UserAccounting.create(anyString(), any(), anyInt(), anyInt()))
- .thenThrow(new EntityExistsException());
- Mockito.when(accountingMock.consumeBudget(anyInt())).thenAnswer((i) -> {
- accountingMock.simulationTime += i.<Integer>getArgument(0);
- return true;
- });
-
- assertFalse(service.consumeSimulationBudget(userId, 10));
- }
-
- @Test
- public void testConsumeBudgetResetSuccess() {
- var periodEnd = LocalDate.now().minusMonths(2);
- var accountingMock = Mockito.spy(new UserAccounting(userId, periodEnd, 3600));
- accountingMock.simulationTime = 3900;
-
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(accountingMock);
- Mockito.when(accountingMock.resetBudget(any(), anyInt())).thenAnswer((i) -> {
- accountingMock.periodEnd = i.getArgument(0);
- accountingMock.simulationTime += i.<Integer>getArgument(1);
- return true;
- });
-
- assertTrue(service.consumeSimulationBudget(userId, 4000));
- }
-
- @Test
- public void testInfiniteConflict() {
- var periodEnd = LocalDate.now().plusMonths(1);
- var accountingMock = Mockito.spy(new UserAccounting(userId, periodEnd, 3600));
-
- Mockito.when(UserAccounting.findByUser(userId)).thenReturn(accountingMock);
- Mockito.when(accountingMock.consumeBudget(anyInt())).thenAnswer((i) -> {
- accountingMock.simulationTime += i.<Integer>getArgument(0);
- return false;
- });
-
- assertThrows(IllegalStateException.class, () -> service.consumeSimulationBudget(userId, 10));
- }
-}
diff --git a/opendc-web/opendc-web-ui-quarkus-deployment/build.gradle.kts b/opendc-web/opendc-web-ui-quarkus-deployment/build.gradle.kts
deleted file mode 100644
index 6be49e22..00000000
--- a/opendc-web/opendc-web-ui-quarkus-deployment/build.gradle.kts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Quarkus extension for serving OpenDC web interface"
-
-// Build configuration
-plugins {
- `java-library-conventions`
-}
-
-dependencies {
- implementation(platform(libs.quarkus.bom))
-
- implementation(projects.opendcWeb.opendcWebUi)
- implementation(projects.opendcWeb.opendcWebUiQuarkus)
-
- implementation(libs.quarkus.core.deployment)
- implementation(libs.quarkus.vertx.http.deployment)
- implementation(libs.quarkus.arc.deployment)
-}
diff --git a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java
deleted file mode 100644
index 82e02549..00000000
--- a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/AuthConfiguration.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.ui.deployment;
-
-import io.quarkus.runtime.annotations.ConfigGroup;
-import io.quarkus.runtime.annotations.ConfigItem;
-import java.util.Optional;
-
-/**
- * Auth configuration for the OpenDC UI extension.
- */
-@ConfigGroup
-public class AuthConfiguration {
- /**
- * The authentication domain.
- */
- @ConfigItem
- Optional<String> domain;
-
- /**
- * The client identifier used by the OpenDC web ui.
- */
- @ConfigItem
- Optional<String> clientId;
-
- /**
- * The audience of the OpenDC API.
- */
- @ConfigItem
- Optional<String> audience;
-}
diff --git a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java
deleted file mode 100644
index 091e60ab..00000000
--- a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiConfig.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.ui.deployment;
-
-import io.quarkus.runtime.annotations.ConfigItem;
-import io.quarkus.runtime.annotations.ConfigRoot;
-import java.util.Optional;
-
-/**
- * Build-time configuration for the OpenDC UI extension.
- */
-@ConfigRoot(name = "opendc-ui")
-public class OpenDCUiConfig {
- /**
- * A flag to include the OpenDC UI extension into the build.
- */
- @ConfigItem(defaultValue = "true")
- boolean include;
-
- /**
- * The base URL of the OpenDC API.
- */
- @ConfigItem(defaultValue = "/api")
- String apiBaseUrl;
-
- /**
- * Configuration properties for web UI authentication.
- */
- AuthConfiguration auth;
-
- /**
- * Sentry DSN.
- */
- @ConfigItem
- Optional<String> sentryDsn;
-}
diff --git a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java
deleted file mode 100644
index 5733e0db..00000000
--- a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiProcessor.java
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.ui.deployment;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import io.quarkus.deployment.annotations.BuildProducer;
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.ExecutionTime;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.builditem.ShutdownContextBuildItem;
-import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;
-import io.quarkus.maven.dependency.GACT;
-import io.quarkus.maven.dependency.ResolvedDependency;
-import io.quarkus.paths.PathVisit;
-import io.quarkus.vertx.http.deployment.HttpRootPathBuildItem;
-import io.quarkus.vertx.http.deployment.RouteBuildItem;
-import io.quarkus.vertx.http.deployment.webjar.WebJarBuildItem;
-import io.quarkus.vertx.http.deployment.webjar.WebJarResourcesFilter;
-import io.quarkus.vertx.http.deployment.webjar.WebJarResultsBuildItem;
-import io.vertx.core.Handler;
-import io.vertx.ext.web.RoutingContext;
-import java.io.*;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.function.BooleanSupplier;
-import java.util.function.Function;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import org.opendc.web.ui.runtime.OpenDCUiRecorder;
-import org.opendc.web.ui.runtime.OpenDCUiRuntimeConfig;
-
-/**
- * Build processor for the OpenDC web UI Quarkus extension.
- */
-public class OpenDCUiProcessor {
-
- private static final String FEATURE = "opendc-ui";
- private static final GACT OPENDC_UI_WEBJAR_ARTIFACT_KEY = new GACT("org.opendc.web", "opendc-web-ui", null, "jar");
- private static final String OPENDC_UI_WEBJAR_STATIC_RESOURCES_PATH = "META-INF/resources/opendc-web-ui";
- private static final Pattern PATH_PARAM_PATTERN = Pattern.compile("\\[(\\w+)]");
-
- private final ObjectMapper objectMapper = new ObjectMapper();
-
- /**
- * Provide the {@link FeatureBuildItem} for this Quarkus extension.
- */
- @BuildStep(onlyIf = IsIncluded.class)
- public FeatureBuildItem feature() {
- return new FeatureBuildItem(FEATURE);
- }
-
- /**
- * Build the WebJar that is used to serve the Next.js resources.
- */
- @BuildStep(onlyIf = IsIncluded.class)
- public WebJarBuildItem buildWebJar(OpenDCUiConfig config) {
- return WebJarBuildItem.builder()
- .artifactKey(OPENDC_UI_WEBJAR_ARTIFACT_KEY)
- .root(OPENDC_UI_WEBJAR_STATIC_RESOURCES_PATH)
- .onlyCopyNonArtifactFiles(false)
- .useDefaultQuarkusBranding(false)
- .filter(new InsertVariablesResourcesFilter(config))
- .build();
- }
-
- /**
- * Build the Next.js routes based on the route manifest generated by it.
- */
- @BuildStep(onlyIf = IsIncluded.class)
- public OpenDCUiRoutingBuildItem buildRoutes(CurateOutcomeBuildItem curateOutcomeBuildItem) throws IOException {
- ResolvedDependency dependency = getAppArtifact(curateOutcomeBuildItem, OPENDC_UI_WEBJAR_ARTIFACT_KEY);
- PathVisit visit = dependency
- .getContentTree()
- .apply(OPENDC_UI_WEBJAR_STATIC_RESOURCES_PATH + "/routes-manifest.json", v -> v);
-
- if (visit == null) {
- throw new FileNotFoundException("Cannot find routes-manifest.json");
- }
-
- JsonNode routeManifest = objectMapper.readTree(visit.getUrl());
-
- var pages = new ArrayList<OpenDCUiRoutingBuildItem.Page>();
- for (Iterator<JsonNode> it = routeManifest.get("staticRoutes").elements(); it.hasNext(); ) {
- JsonNode route = it.next();
-
- String page = route.get("page").asText();
-
- // Static routes do not have any path parameters
- pages.add(new OpenDCUiRoutingBuildItem.Page(page, page));
- }
-
- for (Iterator<JsonNode> it = routeManifest.get("dynamicRoutes").elements(); it.hasNext(); ) {
- JsonNode route = it.next();
-
- String page = route.get("page").asText();
- String path = PATH_PARAM_PATTERN.matcher(page).replaceAll(r -> ":" + r.group(1));
-
- pages.add(new OpenDCUiRoutingBuildItem.Page(path, page));
- }
-
- var redirects = new ArrayList<OpenDCUiRoutingBuildItem.Redirect>();
- for (Iterator<JsonNode> it = routeManifest.get("redirects").elements(); it.hasNext(); ) {
- JsonNode redirect = it.next();
- if (redirect.has("internal")) {
- continue;
- }
-
- int statusCode = redirect.get("statusCode").asInt();
- String path = redirect.get("source").asText();
- String destination = redirect.get("destination").asText();
-
- if (path.isEmpty()) {
- path = "/";
- }
-
- redirects.add(new OpenDCUiRoutingBuildItem.Redirect(path, destination, statusCode));
- }
-
- var custom404 = routeManifest.get("pages404").asBoolean();
- return new OpenDCUiRoutingBuildItem(pages, redirects, custom404);
- }
-
- /**
- * Register the HTTP handles for the OpenDC web UI.
- */
- @BuildStep(onlyIf = IsIncluded.class)
- @Record(ExecutionTime.RUNTIME_INIT)
- public void registerOpenDCUiHandler(
- OpenDCUiRecorder recorder,
- BuildProducer<RouteBuildItem> routes,
- HttpRootPathBuildItem httpRootPathBuildItem,
- WebJarResultsBuildItem webJarResultsBuildItem,
- OpenDCUiRoutingBuildItem openDCUiBuildItem,
- OpenDCUiRuntimeConfig runtimeConfig,
- ShutdownContextBuildItem shutdownContext) {
-
- WebJarResultsBuildItem.WebJarResult result =
- webJarResultsBuildItem.byArtifactKey(OPENDC_UI_WEBJAR_ARTIFACT_KEY);
- if (result == null) {
- return;
- }
-
- String basePath = httpRootPathBuildItem.getRootPath();
- String finalDestination = result.getFinalDestination();
-
- /* Construct dynamic routes */
- for (var redirect : openDCUiBuildItem.getRedirects()) {
- String destination =
- basePath.equals("/") ? redirect.getDestination() : basePath + redirect.getDestination();
-
- routes.produce(httpRootPathBuildItem
- .routeBuilder()
- .route(basePath + redirect.getPath())
- .handler(recorder.redirectHandler(destination, redirect.getStatusCode(), runtimeConfig))
- .build());
- }
-
- for (var page : openDCUiBuildItem.getPages()) {
- routes.produce(httpRootPathBuildItem
- .routeBuilder()
- .route(basePath + page.getPath())
- .handler(recorder.pageHandler(finalDestination, page.getName(), runtimeConfig))
- .build());
- }
-
- /* Construct static routes */
- Handler<RoutingContext> staticHandler = recorder.staticHandler(
- finalDestination, basePath, result.getWebRootConfigurations(), runtimeConfig, shutdownContext);
-
- routes.produce(httpRootPathBuildItem
- .routeBuilder()
- .route("*")
- .handler(staticHandler)
- .build());
- }
-
- /**
- * A {@link WebJarResourcesFilter} that instantiates the variables in the web jar resource.
- */
- private static class InsertVariablesResourcesFilter implements WebJarResourcesFilter {
-
- private static final String HTML = ".html";
- private static final String CSS = ".css";
- private static final String JS = ".js";
-
- private final OpenDCUiConfig config;
-
- public InsertVariablesResourcesFilter(OpenDCUiConfig config) {
- this.config = config;
- }
-
- @Override
- public FilterResult apply(String fileName, InputStream stream) throws IOException {
- if (stream == null) {
- return new FilterResult(null, false);
- }
-
- // Allow replacement of variables in HTML, CSS, and JavaScript files
- if (fileName.endsWith(HTML) || fileName.endsWith(CSS) || fileName.endsWith(JS)) {
- byte[] oldContentBytes = stream.readAllBytes();
- String oldContents = new String(oldContentBytes);
- String contents = substituteVariables(oldContents, this::substitute);
-
- boolean changed = contents.length() != oldContents.length() || !contents.equals(oldContents);
- if (changed) {
- return new FilterResult(new ByteArrayInputStream(contents.getBytes()), true);
- } else {
- return new FilterResult(new ByteArrayInputStream(oldContentBytes), false);
- }
- }
-
- return new FilterResult(stream, false);
- }
-
- private String substitute(String var) {
- switch (var) {
- case "NEXT_PUBLIC_API_BASE_URL":
- return config.apiBaseUrl;
- case "NEXT_PUBLIC_SENTRY_DSN":
- return config.sentryDsn.orElse("");
- case "NEXT_PUBLIC_AUTH0_DOMAIN":
- return config.auth.domain.orElse("");
- case "NEXT_PUBLIC_AUTH0_CLIENT_ID":
- return config.auth.clientId.orElse("");
- case "NEXT_PUBLIC_AUTH0_AUDIENCE":
- return config.auth.audience.orElse("");
- default:
- return null;
- }
- }
-
- /**
- * Pattern to match variables in the OpenDC web UI sources specified using the following format: "%%VAR_NAME%%".
- * <p>
- * Be aware that to properly handle Next.js base path, we need to also match a possible forward slash in front
- * of the variable.
- */
- private static final Pattern PATTERN = Pattern.compile("%%(\\w+)%%");
-
- /**
- * Helper method to substitute variables in the OpenDC web UI.
- */
- private static String substituteVariables(String contents, Function<String, String> substitute) {
- Matcher m = PATTERN.matcher(contents);
- StringBuilder sb = new StringBuilder();
-
- while (m.find()) {
- String group = m.group(1);
- String val = substitute.apply(group);
- m.appendReplacement(sb, val != null ? val : group);
- }
-
- m.appendTail(sb);
- return sb.toString();
- }
- }
-
- /**
- * A {@link BooleanSupplier} to determine if the OpenDC web UI extension should be included.
- */
- private static class IsIncluded implements BooleanSupplier {
- OpenDCUiConfig config;
-
- @Override
- public boolean getAsBoolean() {
- return config.include;
- }
- }
-
- private static ResolvedDependency getAppArtifact(CurateOutcomeBuildItem curateOutcomeBuildItem, GACT artifactKey) {
- for (ResolvedDependency dep :
- curateOutcomeBuildItem.getApplicationModel().getDependencies()) {
- if (dep.getKey().equals(artifactKey)) {
- return dep;
- }
- }
- throw new RuntimeException("Could not find artifact " + artifactKey + " among the application dependencies");
- }
-}
diff --git a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java b/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java
deleted file mode 100644
index 6cf44893..00000000
--- a/opendc-web/opendc-web-ui-quarkus-deployment/src/main/java/org/opendc/web/ui/deployment/OpenDCUiRoutingBuildItem.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.ui.deployment;
-
-import io.quarkus.builder.item.SimpleBuildItem;
-import java.util.List;
-
-/**
- * Build item containing the routes for the OpenDC web UI.
- */
-public final class OpenDCUiRoutingBuildItem extends SimpleBuildItem {
-
- private final boolean custom404;
- private final List<Page> pages;
- private final List<Redirect> redirects;
-
- /**
- * Construct a {@link OpenDCUiRoutingBuildItem} instance.
- *
- * @param routes The routes defined by Next.js.
- * @param redirects The redirects that have been defined by Next.js.
- * @param custom404 A flag to indicate that custom 404 pages are enabled.
- */
- public OpenDCUiRoutingBuildItem(List<Page> routes, List<Redirect> redirects, boolean custom404) {
- this.custom404 = custom404;
- this.pages = routes;
- this.redirects = redirects;
- }
-
- public List<Page> getPages() {
- return pages;
- }
-
- public List<Redirect> getRedirects() {
- return redirects;
- }
-
- public boolean hasCustom404() {
- return this.custom404;
- }
-
- /**
- * A redirect defined by the Next.js routes manifest.
- */
- public static final class Redirect {
-
- private final String path;
- private final String destination;
- private final int statusCode;
-
- /**
- * Construct a {@link Redirect} route.
- *
- * @param path The path that should result in a redirect.
- * @param destination The destination of the redirect.
- * @param statusCode The status code of the redirect.
- */
- public Redirect(String path, String destination, int statusCode) {
- this.statusCode = statusCode;
- this.path = path;
- this.destination = destination;
- }
-
- public String getPath() {
- return path;
- }
-
- public String getDestination() {
- return destination;
- }
-
- public int getStatusCode() {
- return statusCode;
- }
- }
-
- /**
- * A page defined by the Next.js routes manifest.
- */
- public static final class Page {
-
- private final String path;
- private final String name;
-
- public Page(String path, String page) {
- this.path = path;
- this.name = page;
- }
-
- public String getPath() {
- return path;
- }
-
- public String getName() {
- return name;
- }
- }
-}
diff --git a/opendc-web/opendc-web-ui-quarkus/build.gradle.kts b/opendc-web/opendc-web-ui-quarkus/build.gradle.kts
deleted file mode 100644
index 3f8887f6..00000000
--- a/opendc-web/opendc-web-ui-quarkus/build.gradle.kts
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-description = "Quarkus extension for serving OpenDC web interface"
-
-plugins {
- `java-library-conventions`
- id("io.quarkus.extension")
-}
-
-quarkusExtension {
- deploymentModule.set("opendc-web-ui-quarkus-deployment")
-}
-
-dependencies {
- implementation(platform(libs.quarkus.bom))
-
- implementation(libs.quarkus.core.runtime)
- implementation(libs.quarkus.vertx.http.runtime)
- implementation(libs.quarkus.arc.runtime)
-}
-
-evaluationDependsOn(projects.opendcWeb.opendcWebUiQuarkusDeployment.dependencyProject.path)
diff --git a/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java b/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java
deleted file mode 100644
index 03fedd4f..00000000
--- a/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRecorder.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.ui.runtime;
-
-import io.quarkus.runtime.ShutdownContext;
-import io.quarkus.runtime.annotations.Recorder;
-import io.quarkus.vertx.http.runtime.devmode.FileSystemStaticHandler;
-import io.quarkus.vertx.http.runtime.webjar.WebJarNotFoundHandler;
-import io.quarkus.vertx.http.runtime.webjar.WebJarStaticHandler;
-import io.vertx.core.Handler;
-import io.vertx.ext.web.RoutingContext;
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * Helper class for serving the OpenDC web interface.
- */
-@Recorder
-public class OpenDCUiRecorder {
- /**
- * Construct a {@link Handler} for serving a page of the OpenDC web interface.
- */
- public Handler<RoutingContext> pageHandler(
- String finalDestination, String page, OpenDCUiRuntimeConfig runtimeConfig) {
- if (runtimeConfig.enable) {
- String pageDirectory = finalDestination + "/pages";
- return (event) -> {
- event.response().setStatusCode(200).sendFile(pageDirectory + page + ".html");
- };
- }
-
- return new WebJarNotFoundHandler();
- }
-
- /**
- * Construct a {@link Handler} for handling redirects in the OpenDC web interface.
- */
- public Handler<RoutingContext> redirectHandler(
- String destination, int statusCode, OpenDCUiRuntimeConfig runtimeConfig) {
- if (runtimeConfig.enable) {
- return (event) -> {
- String query = event.request().query();
- String fullDestination = query != null ? destination + "?" + query : destination;
-
- event.response()
- .setStatusCode(statusCode)
- .putHeader("Location", fullDestination)
- .end();
- };
- }
-
- return new WebJarNotFoundHandler();
- }
-
- /**
- * Construct a {@link Handler} for serving the static files of the OpenDC web interface.
- */
- public Handler<RoutingContext> staticHandler(
- String finalDestination,
- String path,
- List<FileSystemStaticHandler.StaticWebRootConfiguration> webRootConfigurations,
- OpenDCUiRuntimeConfig runtimeConfig,
- ShutdownContext shutdownContext) {
- if (runtimeConfig.enable) {
- var augmentedWebRootConfigurations = webRootConfigurations.stream()
- .map(c -> new FileSystemStaticHandler.StaticWebRootConfiguration(
- c.getFileSystem(), c.getWebRoot().isEmpty() ? "static" : c.getWebRoot() + "/static"))
- .collect(Collectors.toList());
-
- WebJarStaticHandler handler =
- new WebJarStaticHandler(finalDestination + "/static", path, augmentedWebRootConfigurations);
- shutdownContext.addShutdownTask(new ShutdownContext.CloseRunnable(handler));
- return handler;
- }
-
- return new WebJarNotFoundHandler();
- }
-}
diff --git a/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java b/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java
deleted file mode 100644
index 8ae3b6a2..00000000
--- a/opendc-web/opendc-web-ui-quarkus/src/main/java/org/opendc/web/ui/runtime/OpenDCUiRuntimeConfig.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.web.ui.runtime;
-
-import io.quarkus.runtime.annotations.ConfigItem;
-import io.quarkus.runtime.annotations.ConfigPhase;
-import io.quarkus.runtime.annotations.ConfigRoot;
-
-/**
- * Configuration for the OpenDC web UI.
- */
-@ConfigRoot(phase = ConfigPhase.RUN_TIME, name = "opendc-ui")
-public class OpenDCUiRuntimeConfig {
- /**
- * Flag to indicate whether the web interface should be served by the OpenDC API server.
- */
- @ConfigItem(defaultValue = "true")
- public boolean enable;
-}
diff --git a/opendc-web/opendc-web-ui-quarkus/src/main/resources/META-INF/quarkus-extension.yaml b/opendc-web/opendc-web-ui-quarkus/src/main/resources/META-INF/quarkus-extension.yaml
deleted file mode 100644
index 581a1779..00000000
--- a/opendc-web/opendc-web-ui-quarkus/src/main/resources/META-INF/quarkus-extension.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
----
-name: "OpenDC Web UI"
-metadata:
- status: "preview"
- unlisted: true
diff --git a/opendc-web/opendc-web-ui/.dockerignore b/opendc-web/opendc-web-ui/.dockerignore
deleted file mode 100644
index b91894f6..00000000
--- a/opendc-web/opendc-web-ui/.dockerignore
+++ /dev/null
@@ -1,9 +0,0 @@
-Dockerfile
-
-.idea/
-**/out
-*.iml
-.idea_modules/
-
-node_modules
-build
diff --git a/opendc-web/opendc-web-ui/.eslintrc b/opendc-web/opendc-web-ui/.eslintrc
deleted file mode 100644
index 1446fa02..00000000
--- a/opendc-web/opendc-web-ui/.eslintrc
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "extends": ["next", "eslint:recommended"],
- "env": {
- "browser": true,
- "node": true,
- "es6": true
- },
- "overrides": [
- {
- "files": ["src/**/*.test.js"],
- "env": {
- "jest": true
- }
- }
- ]
-}
diff --git a/opendc-web/opendc-web-ui/.gitignore b/opendc-web/opendc-web-ui/.gitignore
deleted file mode 100644
index 54eada4c..00000000
--- a/opendc-web/opendc-web-ui/.gitignore
+++ /dev/null
@@ -1,27 +0,0 @@
-# Dependencies
-/node_modules
-
-# Testing
-/coverage
-
-# Production
-/build
-
-# Misc
-.DS_Store
-.env.local
-.env.development.local
-.env.test.local
-.env.production.local
-
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-
-# IntelliJ IDEA
-/.idea
-
-# Environment variables
-.env.local
-
-/.next
diff --git a/opendc-web/opendc-web-ui/.prettierrc.yaml b/opendc-web/opendc-web-ui/.prettierrc.yaml
deleted file mode 100644
index 9a2b9a95..00000000
--- a/opendc-web/opendc-web-ui/.prettierrc.yaml
+++ /dev/null
@@ -1,5 +0,0 @@
-trailingComma: "es5"
-tabWidth: 4
-semi: false
-singleQuote: true
-printWidth: 120
diff --git a/opendc-web/opendc-web-ui/Dockerfile b/opendc-web/opendc-web-ui/Dockerfile
deleted file mode 100644
index 24ca2b3e..00000000
--- a/opendc-web/opendc-web-ui/Dockerfile
+++ /dev/null
@@ -1,36 +0,0 @@
-FROM node:18-slim AS staging
-MAINTAINER OpenDC Maintainers <opendc@atlarge-research.com>
-
-# Copy package details
-COPY ./package.json ./package-lock.json /opendc/
-RUN cd /opendc && npm ci
-
-# Build frontend
-FROM node:18-slim AS build
-
-COPY ./ /opendc
-COPY --from=staging /opendc/node_modules /opendc/node_modules
-RUN cd /opendc/ \
- # Environmental variables that will be substituted during image runtime
- && export NEXT_PUBLIC_API_BASE_URL="%%NEXT_PUBLIC_API_BASE_URL%%" \
- NEXT_PUBLIC_SENTRY_DSN="%%NEXT_PUBLIC_SENTRY_DSN%%" \
- NEXT_PUBLIC_AUTH0_DOMAIN="%%NEXT_PUBLIC_AUTH0_DOMAIN%%" \
- NEXT_PUBLIC_AUTH0_CLIENT_ID="%%NEXT_PUBLIC_AUTH0_CLIENT_ID%%" \
- NEXT_PUBLIC_AUTH0_AUDIENCE="%%NEXT_PUBLIC_AUTH0_AUDIENCE%%" \
- && npm run build \
- && npm cache clean --force \
- && mv build/next build/next.template
-
-
-FROM node:18-slim
-COPY --from=build /opendc /opendc
-WORKDIR /opendc
-CMD ./scripts/envsubst.sh; npm run start
-
-LABEL org.opencontainers.image.authors="OpenDC Maintainers <opendc@atlarge-research.com>"
-LABEL org.opencontainers.image.url="https://opendc.org"
-LABEL org.opencontainers.image.documentation="https://opendc.org"
-LABEL org.opencontainers.image.source="https://github.com/atlarge-research/opendc"
-LABEL org.opencontainers.image.title="OpenDC Web UI"
-LABEL org.opencontainers.image.description="OpenDC Web UI Docker Image"
-LABEL org.opencontainers.image.vendor="AtLarge Research"
diff --git a/opendc-web/opendc-web-ui/README.md b/opendc-web/opendc-web-ui/README.md
deleted file mode 100644
index a1133475..00000000
--- a/opendc-web/opendc-web-ui/README.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# OpenDC Web UI
-
-The user-facing component of the OpenDC stack, allowing users to build and interact with their own (virtual)
-datacenters. Built in *React.js* and *Redux*, with the help of [Next.js](https://nextjs.org/).
-
-## Architecture
-
-The codebase follows a standard React.js structure, with static assets being contained in the `public` folder, while
-dynamic components and their styles are contained in `src`.
-
-### Pages
-
-All pages are represented by a component in the `src/pages` directory, following
-the [Next.js conventions](https://nextjs.org/docs/routing/introduction) for routing. There are components for the
-following pages:
-
-1. **index.js** - Entry page (`/`)
-2. **projects/index.js** - Overview of projects of the user (`/projects`)
-3. **projects/[project]/index.js** - Main application, with datacenter construction and simulation UI (`/projects/:projectId`
-and `/projects/:projectId/portfolios/:portfolioId`)
-4. **profile.js** - Profile of the current user (`/profile`)
-5. **404.js** - 404 page to appear when the route is invalid (`/*`)
-
-### Components & Containers
-
-The building blocks of the UI are divided into so-called *components* and *containers*
-([as encouraged](https://medium.com/@dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0) by the author of Redux).
-*Components* are considered 'pure', rendered as a function of input properties. *Containers*, on the other hand,
-are wrappers around *components*, injecting state through the properties of the components they wrap.
-
-Even the canvas (the main component of the app) is built using React components, with the help of the `react-konva`
-module. To illustrate: A rectangular object on the canvas is defined in a way that is not very different from how we
-define a standard `div` element on the splash page.
-
-### API Interaction
-
-The web-app needs to pull data in from the API of a backend running on a server. The functions that call routes are
-located in `src/api`. The actual logic responsible for calling these functions is contained in `src/data`.
-
-### State Management
-
-State for the topology editor is managed via a Redux store. State is kept there in an immutable form, only to be modified through
-actions being dispatched. These actions are contained in the `src/actions` folder, and the reducers (managing how state
-is updated according to dispatched actions) are located in `src/reducers`. If you're not familiar with the Redux
-approach to state management, have a look at their [official documentation](https://redux.js.org/).
-
-## Running the development server
-
-Before we can start the development server, create a file called `.env` in this directory and specify the base URL of
-the API that the React frontend will communicate with. For instance, if you run the OpenDC development server:
-
-```
-NEXT_PUBLIC_API_BASE_URL=http://localhost:8080/api
-```
-
-Now, you're ready to start the Next.js development server. Run the following command in the root of the repository
-(that is, two levels up where the `gradlew` file is located):
-
-```bash
-./gradlew :opendc-web:opendc-web-ui:nextDev
-```
-
-This will start a development server running on [`localhost:3000`](http://localhost:3000), watching for changes you make
-to the code and rebuilding automatically when you save changes.
-
-To compile everything for camera-ready deployment, use the following command:
-
-```bash
-./gradlew :opendc-web:opendc-web-ui:build
-```
-
-You can then run the production server using Next.js as follows:
-
-```bash
-./gradlew :opendc-web:opendc-web-ui:nextStart
-```
-
-## Tests
-
-Files containing tests can be recognized by the `.test.js` suffix. They are usually located right next to the source
-code they are testing, to make discovery easier.
-
-### Running all tests
-
-The following command runs all tests in the codebase using [Jest](https://jest.io). On top of this, it also watches the
-code for changes and reruns the tests whenever any file is saved.
-
-```bash
-./gradlew :opendc-web:opendc-web-ui:test
-```
-
-## Code Quality
-
-We use [Prettier](https://prettier.io) to ensure the formatting of the JavaScript codebase remains consistent. To format
-the files of the codebase according to the preferred coding style, run the following command:
-
-```bash
-./gradlew :opendc-web:opendc-web-ui:prettierFormat
-```
-
-Furthermore, we also employ [ESLint](https://eslint.org/) (via Next) to detect issues and problematic code in our
-codebase. To check for potential issues, run the following command:
-
-```bash
-./gradlew :opendc-web:opendc-web-ui:nextLint
-```
diff --git a/opendc-web/opendc-web-ui/build.gradle.kts b/opendc-web/opendc-web-ui/build.gradle.kts
deleted file mode 100644
index 777098d4..00000000
--- a/opendc-web/opendc-web-ui/build.gradle.kts
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import com.github.gradle.node.npm.task.NpmTask
-
-description = "Web interface for OpenDC"
-
-plugins {
- `java-conventions`
- id("com.github.node-gradle.node")
-}
-
-sourceSets {
- main {
- java.srcDir("src")
- }
- test {
- java.srcDir("test")
- }
-}
-
-node {
- download.set(true)
- version.set(libs.versions.node.get())
-}
-
-val formatTask =
- tasks.register<NpmTask>("prettierFormat") {
- group = "formatting"
- description = "Use Prettier to format the JavaScript codebase"
-
- args.set(listOf("run", "format"))
- dependsOn(tasks.npmInstall)
- inputs.dir("src")
- inputs.files("package.json", "next.config.js", ".prettierrc.yaml")
- outputs.upToDateWhen { true }
- }
-
-val lintTask =
- tasks.register<NpmTask>("nextLint") {
- group = "verification"
- description = "Use ESLint to check for problems"
-
- args.set(listOf("run", "lint"))
- dependsOn(tasks.npmInstall)
- inputs.dir("src")
- inputs.files("package.json", "next.config.js", ".eslintrc")
- outputs.upToDateWhen { true }
- }
-
-tasks.register<NpmTask>("nextDev") {
- group = "build"
- description = "Run the Next.js project in development mode"
-
- args.set(listOf("run", "dev"))
- dependsOn(tasks.npmInstall)
- inputs.dir(project.fileTree("src"))
- inputs.dir("node_modules")
- inputs.files("package.json", "next.config.js")
- outputs.upToDateWhen { true }
-}
-
-val buildTask =
- tasks.register<NpmTask>("nextBuild") {
- group = "build"
- description = "Build the Next.js project"
-
- args.set(listOf("run", "build"))
-
- val env =
- listOf(
- "NEXT_PUBLIC_API_BASE_URL",
- "NEXT_PUBLIC_SENTRY_DSN",
- "NEXT_PUBLIC_AUTH0_DOMAIN",
- "NEXT_PUBLIC_AUTH0_CLIENT_ID",
- "NEXT_PUBLIC_AUTH0_AUDIENCE",
- )
- for (envvar in env) {
- environment.put(envvar, "%%$envvar%%")
- }
-
- dependsOn(tasks.npmInstall)
- inputs.dir(project.fileTree("src"))
- inputs.dir("node_modules")
- inputs.files("package.json", "next.config.js")
- outputs.dir(layout.buildDirectory.dir("next"))
- }
-
-tasks.register<NpmTask>("nextStart") {
- group = "build"
- description = "Build the Next.js project"
-
- args.set(listOf("run", "start"))
-
- dependsOn(buildTask)
- dependsOn(tasks.npmInstall)
-
- inputs.dir(project.fileTree("src"))
- inputs.dir("node_modules")
- inputs.files("package.json", "next.config.js")
- outputs.upToDateWhen { true }
-}
-
-tasks.processResources {
- dependsOn(buildTask)
- inputs.dir(project.fileTree("public"))
-
- from(layout.buildDirectory.dir("next")) {
- include("routes-manifest.json")
- into("META-INF/resources/${project.name}")
- }
-
- from(layout.buildDirectory.dir("next/static")) {
- into("META-INF/resources/${project.name}/static/_next/static")
- }
-
- from(layout.buildDirectory.dir("next/server/pages")) {
- include("**/*.html")
- into("META-INF/resources/${project.name}/pages")
- }
-
- from(project.fileTree("public")) {
- into("META-INF/resources/${project.name}/static")
- }
-}
diff --git a/opendc-web/opendc-web-ui/next.config.js b/opendc-web/opendc-web-ui/next.config.js
deleted file mode 100644
index f761ba74..00000000
--- a/opendc-web/opendc-web-ui/next.config.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-// PatternFly 4 uses global CSS imports in its distribution files. Therefore,
-// we need to transpile the modules before we can use them.
-const { withGlobalCss } = require('next-global-css')
-const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");
-const withConfig = withGlobalCss()
-
-module.exports = (phase) => withConfig({
- basePath: process.env.NEXT_BASE_PATH && '/' + process.env.NEXT_BASE_PATH,
- reactStrictMode: true,
- distDir: phase === PHASE_DEVELOPMENT_SERVER ? 'build/next-dev' : 'build/next',
- async redirects() {
- return [
- {
- source: '/',
- destination: '/projects',
- permanent: false
- }
- ]
- },
- images: { unoptimized: true }
-})
diff --git a/opendc-web/opendc-web-ui/package-lock.json b/opendc-web/opendc-web-ui/package-lock.json
deleted file mode 100644
index 5d78081e..00000000
--- a/opendc-web/opendc-web-ui/package-lock.json
+++ /dev/null
@@ -1,4665 +0,0 @@
-{
- "name": "opendc-frontend",
- "version": "3.0.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "opendc-frontend",
- "version": "3.0.0",
- "license": "MIT",
- "dependencies": {
- "@auth0/auth0-react": "^1.12.1",
- "@patternfly/react-charts": "^6.94.18",
- "@patternfly/react-core": "^4.276.6",
- "@patternfly/react-icons": "^4.93.6",
- "@patternfly/react-table": "^4.112.39",
- "@sentry/react": "^7.45.0",
- "@sentry/tracing": "^7.45.0",
- "clsx": "^1.2.1",
- "immer": "^9.0.21",
- "konva": "^8.4.3",
- "mathjs": "^11.7.0",
- "next": "^13.5.4",
- "next-global-css": "^1.3.1",
- "normalizr": "^3.6.2",
- "prettier": "^2.8.7",
- "prop-types": "^15.8.1",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-hotkeys-hook": "^4.3.8",
- "react-konva": "^18.2.5",
- "react-query": "^3.39.3",
- "react-redux": "^8.0.5",
- "redux": "^4.2.1",
- "redux-logger": "^3.0.6",
- "redux-saga": "^1.2.3",
- "redux-thunk": "^2.4.2",
- "svgsaver": "^0.9.0",
- "use-resize-observer": "^9.1.0",
- "uuid": "^9.0.0",
- "victory-errorbar": "^36.6.8"
- },
- "devDependencies": {
- "eslint": "^8.36.0",
- "eslint-config-next": "^13.2.4"
- }
- },
- "node_modules/@auth0/auth0-react": {
- "version": "1.12.1",
- "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-1.12.1.tgz",
- "integrity": "sha512-8+ecK/4rE0AGsxLW2IDcr1oPbT55tuE6cQEzEIOkQjB6QGQxxWMzQy0D4nMKw3JUAc7nYcFVOABNFNbc471n9Q==",
- "dependencies": {
- "@auth0/auth0-spa-js": "^1.22.6"
- },
- "peerDependencies": {
- "react": "^16.11.0 || ^17 || ^18",
- "react-dom": "^16.11.0 || ^17 || ^18"
- }
- },
- "node_modules/@auth0/auth0-spa-js": {
- "version": "1.22.6",
- "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.22.6.tgz",
- "integrity": "sha512-iL3O0vWanfKFVgy1J2ZHDPlAUK6EVHWEHWS6mUXwHEuPiK39tjlQtyUKQIJI1F5YsZB75ijGgRWMTawSDXlwCA==",
- "dependencies": {
- "abortcontroller-polyfill": "^1.7.3",
- "browser-tabs-lock": "^1.2.15",
- "core-js": "^3.25.4",
- "es-cookie": "~1.3.2",
- "fast-text-encoding": "^1.0.6",
- "promise-polyfill": "^8.2.3",
- "unfetch": "^4.2.0"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.21.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
- "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
- "dependencies": {
- "regenerator-runtime": "^0.13.11"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/runtime-corejs3": {
- "version": "7.19.6",
- "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.6.tgz",
- "integrity": "sha512-oWNn1ZlGde7b4i/3tnixpH9qI0bOAACiUs+KEES4UUCnsPjVWFlWdLV/iwJuPC2qp3EowbAqsm+0XqNwnwYhxA==",
- "dev": true,
- "dependencies": {
- "core-js-pure": "^3.25.1",
- "regenerator-runtime": "^0.13.4"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@eslint-community/eslint-utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
- "dev": true,
- "dependencies": {
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
- }
- },
- "node_modules/@eslint-community/regexpp": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.4.1.tgz",
- "integrity": "sha512-BISJ6ZE4xQsuL/FmsyRaiffpq977bMlsKfGHTQrOGFErfByxIe6iZTxPf/00Zon9b9a7iUykfQwejN3s2ZW/Bw==",
- "dev": true,
- "engines": {
- "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
- }
- },
- "node_modules/@eslint/eslintrc": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.1.tgz",
- "integrity": "sha512-eFRmABvW2E5Ho6f5fHLqgena46rOj7r7OKHYfLElqcBfGFHHpjBhivyi5+jOEQuSpdc/1phIZJlbC2te+tZNIw==",
- "dev": true,
- "dependencies": {
- "ajv": "^6.12.4",
- "debug": "^4.3.2",
- "espree": "^9.5.0",
- "globals": "^13.19.0",
- "ignore": "^5.2.0",
- "import-fresh": "^3.2.1",
- "js-yaml": "^4.1.0",
- "minimatch": "^3.1.2",
- "strip-json-comments": "^3.1.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/@eslint/js": {
- "version": "8.36.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz",
- "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.11.8",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
- "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==",
- "dev": true,
- "dependencies": {
- "@humanwhocodes/object-schema": "^1.2.1",
- "debug": "^4.1.1",
- "minimatch": "^3.0.5"
- },
- "engines": {
- "node": ">=10.10.0"
- }
- },
- "node_modules/@humanwhocodes/module-importer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
- "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
- "dev": true,
- "engines": {
- "node": ">=12.22"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/nzakas"
- }
- },
- "node_modules/@humanwhocodes/object-schema": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
- "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
- "dev": true
- },
- "node_modules/@juggle/resize-observer": {
- "version": "3.4.0",
- "resolved": "https://registry.npmjs.org/@juggle/resize-observer/-/resize-observer-3.4.0.tgz",
- "integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
- },
- "node_modules/@next/env": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-13.5.4.tgz",
- "integrity": "sha512-LGegJkMvRNw90WWphGJ3RMHMVplYcOfRWf2Be3td3sUa+1AaxmsYyANsA+znrGCBjXJNi4XAQlSoEfUxs/4kIQ=="
- },
- "node_modules/@next/eslint-plugin-next": {
- "version": "13.2.4",
- "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-13.2.4.tgz",
- "integrity": "sha512-ck1lI+7r1mMJpqLNa3LJ5pxCfOB1lfJncKmRJeJxcJqcngaFwylreLP7da6Rrjr6u2gVRTfmnkSkjc80IiQCwQ==",
- "dev": true,
- "dependencies": {
- "glob": "7.1.7"
- }
- },
- "node_modules/@next/swc-darwin-arm64": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.5.4.tgz",
- "integrity": "sha512-Df8SHuXgF1p+aonBMcDPEsaahNo2TCwuie7VXED4FVyECvdXfRT9unapm54NssV9tF3OQFKBFOdlje4T43VO0w==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-darwin-x64": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.5.4.tgz",
- "integrity": "sha512-siPuUwO45PnNRMeZnSa8n/Lye5ZX93IJom9wQRB5DEOdFrw0JjOMu1GINB8jAEdwa7Vdyn1oJ2xGNaQpdQQ9Pw==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-arm64-gnu": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.5.4.tgz",
- "integrity": "sha512-l/k/fvRP/zmB2jkFMfefmFkyZbDkYW0mRM/LB+tH5u9pB98WsHXC0WvDHlGCYp3CH/jlkJPL7gN8nkTQVrQ/2w==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-arm64-musl": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.5.4.tgz",
- "integrity": "sha512-YYGb7SlLkI+XqfQa8VPErljb7k9nUnhhRrVaOdfJNCaQnHBcvbT7cx/UjDQLdleJcfyg1Hkn5YSSIeVfjgmkTg==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-x64-gnu": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.5.4.tgz",
- "integrity": "sha512-uE61vyUSClnCH18YHjA8tE1prr/PBFlBFhxBZis4XBRJoR+txAky5d7gGNUIbQ8sZZ7LVkSVgm/5Fc7mwXmRAg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-linux-x64-musl": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.5.4.tgz",
- "integrity": "sha512-qVEKFYML/GvJSy9CfYqAdUexA6M5AklYcQCW+8JECmkQHGoPxCf04iMh7CPR7wkHyWWK+XLt4Ja7hhsPJtSnhg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "linux"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-arm64-msvc": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.5.4.tgz",
- "integrity": "sha512-mDSQfqxAlfpeZOLPxLymZkX0hYF3juN57W6vFHTvwKlnHfmh12Pt7hPIRLYIShk8uYRsKPtMTth/EzpwRI+u8w==",
- "cpu": [
- "arm64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-ia32-msvc": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.5.4.tgz",
- "integrity": "sha512-aoqAT2XIekIWoriwzOmGFAvTtVY5O7JjV21giozBTP5c6uZhpvTWRbmHXbmsjZqY4HnEZQRXWkSAppsIBweKqw==",
- "cpu": [
- "ia32"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@next/swc-win32-x64-msvc": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.5.4.tgz",
- "integrity": "sha512-cyRvlAxwlddlqeB9xtPSfNSCRy8BOa4wtMo0IuI9P7Y0XT2qpDrpFKRyZ7kUngZis59mPVla5k8X1oOJ8RxDYg==",
- "cpu": [
- "x64"
- ],
- "optional": true,
- "os": [
- "win32"
- ],
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/@nodelib/fs.scandir": {
- "version": "2.1.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
- "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.stat": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
- "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@nodelib/fs.walk": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
- "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@patternfly/react-charts": {
- "version": "6.94.18",
- "resolved": "https://registry.npmjs.org/@patternfly/react-charts/-/react-charts-6.94.18.tgz",
- "integrity": "sha512-56WxnZYC3blRX41mW67JaPxJ3YhXViLvwGpEsZrYCccla/rTV8JgKK0gjHnqtzPQiVBfpn+3ewOyNCOR5uRoSw==",
- "dependencies": {
- "@patternfly/react-styles": "^4.92.6",
- "@patternfly/react-tokens": "^4.94.6",
- "hoist-non-react-statics": "^3.3.0",
- "lodash": "^4.17.19",
- "tslib": "^2.0.0",
- "victory-area": "^36.6.7",
- "victory-axis": "^36.6.7",
- "victory-bar": "^36.6.7",
- "victory-chart": "^36.6.7",
- "victory-core": "^36.6.7",
- "victory-create-container": "^36.6.7",
- "victory-cursor-container": "^36.6.7",
- "victory-group": "^36.6.7",
- "victory-legend": "^36.6.7",
- "victory-line": "^36.6.7",
- "victory-pie": "^36.6.7",
- "victory-scatter": "^36.6.7",
- "victory-stack": "^36.6.7",
- "victory-tooltip": "^36.6.7",
- "victory-voronoi-container": "^36.6.7",
- "victory-zoom-container": "^36.6.7"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17 || ^18",
- "react-dom": "^16.8 || ^17 || ^18"
- }
- },
- "node_modules/@patternfly/react-core": {
- "version": "4.276.6",
- "resolved": "https://registry.npmjs.org/@patternfly/react-core/-/react-core-4.276.6.tgz",
- "integrity": "sha512-G0K+378jf9jw9g+hCAoKnsAe/UGTRspqPeuAYypF2FgNr+dC7dUpc7/VkNhZBVqSJzUWVEK8NyXcqkfi0IemIg==",
- "dependencies": {
- "@patternfly/react-icons": "^4.93.6",
- "@patternfly/react-styles": "^4.92.6",
- "@patternfly/react-tokens": "^4.94.6",
- "focus-trap": "6.9.2",
- "react-dropzone": "9.0.0",
- "tippy.js": "5.1.2",
- "tslib": "^2.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17 || ^18",
- "react-dom": "^16.8 || ^17 || ^18"
- }
- },
- "node_modules/@patternfly/react-icons": {
- "version": "4.93.6",
- "resolved": "https://registry.npmjs.org/@patternfly/react-icons/-/react-icons-4.93.6.tgz",
- "integrity": "sha512-ZrXegc/81oiuTIeWvoHb3nG/eZODbB4rYmekBEsrbiysyO7m/sUFoi/RLvgFINrRoh6YCJqL5fj06Jg6d7jX1g==",
- "peerDependencies": {
- "react": "^16.8 || ^17 || ^18",
- "react-dom": "^16.8 || ^17 || ^18"
- }
- },
- "node_modules/@patternfly/react-styles": {
- "version": "4.92.6",
- "resolved": "https://registry.npmjs.org/@patternfly/react-styles/-/react-styles-4.92.6.tgz",
- "integrity": "sha512-b8uQdEReMyeoMzjpMri845QxqtupY/tIFFYfVeKoB2neno8gkcW1RvDdDe62LF88q45OktCwAe/8A99ker10Iw=="
- },
- "node_modules/@patternfly/react-table": {
- "version": "4.112.39",
- "resolved": "https://registry.npmjs.org/@patternfly/react-table/-/react-table-4.112.39.tgz",
- "integrity": "sha512-U+hOMgYlbghGH4M5MX+qt0GkVi/ocrGnxDnm11YiS3CtEGsd6Rr0NeqMmk0uoR46Od4Pr5tKuXxZhPP32sCL/w==",
- "dependencies": {
- "@patternfly/react-core": "^4.276.6",
- "@patternfly/react-icons": "^4.93.6",
- "@patternfly/react-styles": "^4.92.6",
- "@patternfly/react-tokens": "^4.94.6",
- "lodash": "^4.17.19",
- "tslib": "^2.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17 || ^18",
- "react-dom": "^16.8 || ^17 || ^18"
- }
- },
- "node_modules/@patternfly/react-tokens": {
- "version": "4.94.6",
- "resolved": "https://registry.npmjs.org/@patternfly/react-tokens/-/react-tokens-4.94.6.tgz",
- "integrity": "sha512-tm7C6nat+uKMr1hrapis7hS3rN9cr41tpcCKhx6cod6FLU8KwF2Yt5KUxakhIOCEcE/M/EhXhAw/qejp8w0r7Q=="
- },
- "node_modules/@pkgr/utils": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.3.1.tgz",
- "integrity": "sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "is-glob": "^4.0.3",
- "open": "^8.4.0",
- "picocolors": "^1.0.0",
- "tiny-glob": "^0.2.9",
- "tslib": "^2.4.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/unts"
- }
- },
- "node_modules/@redux-saga/core": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@redux-saga/core/-/core-1.2.3.tgz",
- "integrity": "sha512-U1JO6ncFBAklFTwoQ3mjAeQZ6QGutsJzwNBjgVLSWDpZTRhobUzuVDS1qH3SKGJD8fvqoaYOjp6XJ3gCmeZWgA==",
- "dependencies": {
- "@babel/runtime": "^7.6.3",
- "@redux-saga/deferred": "^1.2.1",
- "@redux-saga/delay-p": "^1.2.1",
- "@redux-saga/is": "^1.1.3",
- "@redux-saga/symbols": "^1.1.3",
- "@redux-saga/types": "^1.2.1",
- "redux": "^4.0.4",
- "typescript-tuple": "^2.2.1"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/redux-saga"
- }
- },
- "node_modules/@redux-saga/deferred": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@redux-saga/deferred/-/deferred-1.2.1.tgz",
- "integrity": "sha512-cmin3IuuzMdfQjA0lG4B+jX+9HdTgHZZ+6u3jRAOwGUxy77GSlTi4Qp2d6PM1PUoTmQUR5aijlA39scWWPF31g=="
- },
- "node_modules/@redux-saga/delay-p": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@redux-saga/delay-p/-/delay-p-1.2.1.tgz",
- "integrity": "sha512-MdiDxZdvb1m+Y0s4/hgdcAXntpUytr9g0hpcOO1XFVyyzkrDu3SKPgBFOtHn7lhu7n24ZKIAT1qtKyQjHqRd+w==",
- "dependencies": {
- "@redux-saga/symbols": "^1.1.3"
- }
- },
- "node_modules/@redux-saga/is": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@redux-saga/is/-/is-1.1.3.tgz",
- "integrity": "sha512-naXrkETG1jLRfVfhOx/ZdLj0EyAzHYbgJWkXbB3qFliPcHKiWbv/ULQryOAEKyjrhiclmr6AMdgsXFyx7/yE6Q==",
- "dependencies": {
- "@redux-saga/symbols": "^1.1.3",
- "@redux-saga/types": "^1.2.1"
- }
- },
- "node_modules/@redux-saga/symbols": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/@redux-saga/symbols/-/symbols-1.1.3.tgz",
- "integrity": "sha512-hCx6ZvU4QAEUojETnX8EVg4ubNLBFl1Lps4j2tX7o45x/2qg37m3c6v+kSp8xjDJY+2tJw4QB3j8o8dsl1FDXg=="
- },
- "node_modules/@redux-saga/types": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@redux-saga/types/-/types-1.2.1.tgz",
- "integrity": "sha512-1dgmkh+3so0+LlBWRhGA33ua4MYr7tUOj+a9Si28vUi0IUFNbff1T3sgpeDJI/LaC75bBYnQ0A3wXjn0OrRNBA=="
- },
- "node_modules/@rushstack/eslint-patch": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz",
- "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==",
- "dev": true
- },
- "node_modules/@sentry-internal/tracing": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.45.0.tgz",
- "integrity": "sha512-0aIDY2OvUX7k2XHaimOlWkboXoQvJ9dEKvfpu0Wh0YxfUTGPa+wplUdg3WVdkk018sq1L11MKmj4MPZyYUvXhw==",
- "dependencies": {
- "@sentry/core": "7.45.0",
- "@sentry/types": "7.45.0",
- "@sentry/utils": "7.45.0",
- "tslib": "^1.9.3"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@sentry-internal/tracing/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "node_modules/@sentry/browser": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.45.0.tgz",
- "integrity": "sha512-/dUrUwnI34voMj+jSJT7b5Jun+xy1utVyzzwTq3Oc22N+SB17ZOX9svZ4jl1Lu6tVJPVjPyvL6zlcbrbMwqFjg==",
- "dependencies": {
- "@sentry-internal/tracing": "7.45.0",
- "@sentry/core": "7.45.0",
- "@sentry/replay": "7.45.0",
- "@sentry/types": "7.45.0",
- "@sentry/utils": "7.45.0",
- "tslib": "^1.9.3"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@sentry/browser/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "node_modules/@sentry/core": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.45.0.tgz",
- "integrity": "sha512-xJfdTS4lRmHvZI/A5MazdnKhBJFkisKu6G9EGNLlZLre+6W4PH5sb7QX4+xoBdqG7v10Jvdia112vi762ojO2w==",
- "dependencies": {
- "@sentry/types": "7.45.0",
- "@sentry/utils": "7.45.0",
- "tslib": "^1.9.3"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@sentry/core/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "node_modules/@sentry/react": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.45.0.tgz",
- "integrity": "sha512-Dbz85nfvMUikbLHUuIt6fBNPmTvThFn+rWB5KS1NIOJifyWAdpIU3X7yCUJE5xhsUObNLiHlNJlqhaQI4nR1bQ==",
- "dependencies": {
- "@sentry/browser": "7.45.0",
- "@sentry/types": "7.45.0",
- "@sentry/utils": "7.45.0",
- "hoist-non-react-statics": "^3.3.2",
- "tslib": "^1.9.3"
- },
- "engines": {
- "node": ">=8"
- },
- "peerDependencies": {
- "react": "15.x || 16.x || 17.x || 18.x"
- }
- },
- "node_modules/@sentry/react/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "node_modules/@sentry/replay": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.45.0.tgz",
- "integrity": "sha512-smM7FIcFIyKu30BqCl8BzLo1gH/z9WwXdGX6V0fNvHab9fJZ09+xjFn+LmIyo6N8H8jjwsup0+yQ12kiF/ZsEw==",
- "dependencies": {
- "@sentry/core": "7.45.0",
- "@sentry/types": "7.45.0",
- "@sentry/utils": "7.45.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@sentry/tracing": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.45.0.tgz",
- "integrity": "sha512-FsoFmZPzTBGvWeJH73NxSF1ot61Zw3aIZo5XolengiKnRmcrQOFxebtMKBiZ61QBRYGqsm5uT7QB7zITU6Ikgg==",
- "dependencies": {
- "@sentry-internal/tracing": "7.45.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@sentry/types": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.45.0.tgz",
- "integrity": "sha512-iFt7msfUK8LCodFF3RKUyaxy9tJv/gpWhzxUFyNxtuVwlpmd+q6mtsFGn8Af3pbpm8A+MKyz1ebMwXj0PQqknw==",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@sentry/utils": {
- "version": "7.45.0",
- "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.45.0.tgz",
- "integrity": "sha512-aTY7qqtNUudd09SH5DVSKMm3iQ6ZeWufduc0I9bPZe6UMM09BDc4KmjmrzRkdQ+VaOmHo7+v+HZKQk5f+AbuTQ==",
- "dependencies": {
- "@sentry/types": "7.45.0",
- "tslib": "^1.9.3"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@sentry/utils/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
- },
- "node_modules/@swc/helpers": {
- "version": "0.5.2",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz",
- "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==",
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@types/d3-array": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz",
- "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ=="
- },
- "node_modules/@types/d3-color": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz",
- "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA=="
- },
- "node_modules/@types/d3-ease": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.0.tgz",
- "integrity": "sha512-aMo4eaAOijJjA6uU+GIeW018dvy9+oH5Y2VPPzjjfxevvGQ/oRDs+tfYC9b50Q4BygRR8yE2QCLsrT0WtAVseA=="
- },
- "node_modules/@types/d3-interpolate": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
- "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==",
- "dependencies": {
- "@types/d3-color": "*"
- }
- },
- "node_modules/@types/d3-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.0.0.tgz",
- "integrity": "sha512-0g/A+mZXgFkQxN3HniRDbXMN79K3CdTpLsevj+PXiTcb2hVyvkZUBg37StmgCQkaD84cUJ4uaDAWq7UJOQy2Tg=="
- },
- "node_modules/@types/d3-scale": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz",
- "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==",
- "dependencies": {
- "@types/d3-time": "*"
- }
- },
- "node_modules/@types/d3-shape": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.0.tgz",
- "integrity": "sha512-jYIYxFFA9vrJ8Hd4Se83YI6XF+gzDL1aC5DCsldai4XYYiVNdhtpGbA/GM6iyQ8ayhSp3a148LY34hy7A4TxZA==",
- "dependencies": {
- "@types/d3-path": "*"
- }
- },
- "node_modules/@types/d3-time": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz",
- "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg=="
- },
- "node_modules/@types/d3-timer": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.0.tgz",
- "integrity": "sha512-HNB/9GHqu7Fo8AQiugyJbv6ZxYz58wef0esl4Mv828w1ZKpAshw/uFWVDUcIB9KKFeFKoxS3cHY07FFgtTRZ1g=="
- },
- "node_modules/@types/hoist-non-react-statics": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
- "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
- "dependencies": {
- "@types/react": "*",
- "hoist-non-react-statics": "^3.3.0"
- }
- },
- "node_modules/@types/json5": {
- "version": "0.0.29",
- "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
- "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
- "dev": true
- },
- "node_modules/@types/prop-types": {
- "version": "15.7.5",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
- "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w=="
- },
- "node_modules/@types/react": {
- "version": "18.0.23",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.23.tgz",
- "integrity": "sha512-R1wTULtCiJkudAN2DJGoYYySbGtOdzZyUWAACYinKdiQC8auxso4kLDUhQ7AJ2kh3F6A6z4v69U6tNY39hihVQ==",
- "dependencies": {
- "@types/prop-types": "*",
- "@types/scheduler": "*",
- "csstype": "^3.0.2"
- }
- },
- "node_modules/@types/react-reconciler": {
- "version": "0.28.2",
- "resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.2.tgz",
- "integrity": "sha512-8tu6lHzEgYPlfDf/J6GOQdIc+gs+S2yAqlby3zTsB3SP2svlqTYe5fwZNtZyfactP74ShooP2vvi1BOp9ZemWw==",
- "dependencies": {
- "@types/react": "*"
- }
- },
- "node_modules/@types/scheduler": {
- "version": "0.16.2",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz",
- "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
- },
- "node_modules/@types/use-sync-external-store": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz",
- "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA=="
- },
- "node_modules/@typescript-eslint/parser": {
- "version": "5.42.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.42.1.tgz",
- "integrity": "sha512-kAV+NiNBWVQDY9gDJDToTE/NO8BHi4f6b7zTsVAJoTkmB/zlfOpiEVBzHOKtlgTndCKe8vj9F/PuolemZSh50Q==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/scope-manager": "5.42.1",
- "@typescript-eslint/types": "5.42.1",
- "@typescript-eslint/typescript-estree": "5.42.1",
- "debug": "^4.3.4"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependencies": {
- "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "5.42.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.42.1.tgz",
- "integrity": "sha512-QAZY/CBP1Emx4rzxurgqj3rUinfsh/6mvuKbLNMfJMMKYLRBfweus8brgXF8f64ABkIZ3zdj2/rYYtF8eiuksQ==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.42.1",
- "@typescript-eslint/visitor-keys": "5.42.1"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/types": {
- "version": "5.42.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.42.1.tgz",
- "integrity": "sha512-Qrco9dsFF5lhalz+lLFtxs3ui1/YfC6NdXu+RAGBa8uSfn01cjO7ssCsjIsUs484vny9Xm699FSKwpkCcqwWwA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "5.42.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.42.1.tgz",
- "integrity": "sha512-qElc0bDOuO0B8wDhhW4mYVgi/LZL+igPwXtV87n69/kYC/7NG3MES0jHxJNCr4EP7kY1XVsRy8C/u3DYeTKQmw==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.42.1",
- "@typescript-eslint/visitor-keys": "5.42.1",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "semver": "^7.3.7",
- "tsutils": "^3.21.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "5.42.1",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.42.1.tgz",
- "integrity": "sha512-LOQtSF4z+hejmpUvitPlc4hA7ERGoj2BVkesOcG91HCn8edLGUXbTrErmutmPbl8Bo9HjAvOO/zBKQHExXNA2A==",
- "dev": true,
- "dependencies": {
- "@typescript-eslint/types": "5.42.1",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- }
- },
- "node_modules/abortcontroller-polyfill": {
- "version": "1.7.5",
- "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz",
- "integrity": "sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ=="
- },
- "node_modules/acorn": {
- "version": "8.8.2",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
- "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
- "dev": true,
- "bin": {
- "acorn": "bin/acorn"
- },
- "engines": {
- "node": ">=0.4.0"
- }
- },
- "node_modules/acorn-jsx": {
- "version": "5.3.2",
- "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
- "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
- "dev": true,
- "peerDependencies": {
- "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
- }
- },
- "node_modules/ajv": {
- "version": "6.12.6",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
- "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
- "dev": true,
- "dependencies": {
- "fast-deep-equal": "^3.1.1",
- "fast-json-stable-stringify": "^2.0.0",
- "json-schema-traverse": "^0.4.1",
- "uri-js": "^4.2.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/epoberezkin"
- }
- },
- "node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/argparse": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
- "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
- "dev": true
- },
- "node_modules/aria-query": {
- "version": "4.2.2",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz",
- "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.10.2",
- "@babel/runtime-corejs3": "^7.10.2"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/array-includes": {
- "version": "3.1.6",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
- "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "get-intrinsic": "^1.1.3",
- "is-string": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/array.prototype.flat": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz",
- "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-shim-unscopables": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array.prototype.flatmap": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
- "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4",
- "es-shim-unscopables": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/ast-types-flow": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
- "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==",
- "dev": true
- },
- "node_modules/attr-accept": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/attr-accept/-/attr-accept-1.1.3.tgz",
- "integrity": "sha512-iT40nudw8zmCweivz6j58g+RT33I4KbaIvRUhjNmDwO2WmsQUxFEZZYZ5w3vXe5x5MX9D7mfvA/XaLOZYFR9EQ==",
- "dependencies": {
- "core-js": "^2.5.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/attr-accept/node_modules/core-js": {
- "version": "2.6.12",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",
- "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==",
- "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js.",
- "hasInstallScript": true
- },
- "node_modules/axe-core": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.5.0.tgz",
- "integrity": "sha512-4+rr8eQ7+XXS5nZrKcMO/AikHL0hVqy+lHWAnE3xdHl+aguag8SOQ6eEqLexwLNWgXIMfunGuD3ON1/6Kyet0A==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/axobject-query": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz",
- "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==",
- "dev": true
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
- },
- "node_modules/big-integer": {
- "version": "1.6.51",
- "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
- "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
- "engines": {
- "node": ">=0.6"
- }
- },
- "node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/braces": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
- "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/broadcast-channel": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/broadcast-channel/-/broadcast-channel-3.7.0.tgz",
- "integrity": "sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==",
- "dependencies": {
- "@babel/runtime": "^7.7.2",
- "detect-node": "^2.1.0",
- "js-sha3": "0.8.0",
- "microseconds": "0.2.0",
- "nano-time": "1.0.0",
- "oblivious-set": "1.0.0",
- "rimraf": "3.0.2",
- "unload": "2.2.0"
- }
- },
- "node_modules/browser-tabs-lock": {
- "version": "1.2.15",
- "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.15.tgz",
- "integrity": "sha512-J8K9vdivK0Di+b8SBdE7EZxDr88TnATing7XoLw6+nFkXMQ6sVBh92K3NQvZlZU91AIkFRi0w3sztk5Z+vsswA==",
- "hasInstallScript": true,
- "dependencies": {
- "lodash": ">=4.17.21"
- }
- },
- "node_modules/busboy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
- "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
- "dependencies": {
- "streamsearch": "^1.1.0"
- },
- "engines": {
- "node": ">=10.16.0"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
- "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1",
- "get-intrinsic": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/callsites": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
- "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/caniuse-lite": {
- "version": "1.0.30001426",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001426.tgz",
- "integrity": "sha512-n7cosrHLl8AWt0wwZw/PJZgUg3lV0gk9LMI7ikGJwhyhgsd2Nb65vKvmSexCqq/J7rbH3mFG6yZZiPR5dLPW5A==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/browserslist"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
- }
- ]
- },
- "node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/client-only": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
- "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
- },
- "node_modules/clsx": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
- "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/complex.js": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.1.1.tgz",
- "integrity": "sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==",
- "engines": {
- "node": "*"
- },
- "funding": {
- "type": "patreon",
- "url": "https://www.patreon.com/infusion"
- }
- },
- "node_modules/computed-styles": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/computed-styles/-/computed-styles-1.1.2.tgz",
- "integrity": "sha512-CGbti1B791SKg6goVX0cSI++hFBSzY9+7+lhX8lqXDI5FHexluglI1cPtvIifS4mEcWxPJ+HKYPr2t6nqz7PxA=="
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
- },
- "node_modules/core-js": {
- "version": "3.29.1",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.29.1.tgz",
- "integrity": "sha512-+jwgnhg6cQxKYIIjGtAHq2nwUOolo9eoFZ4sHfUH09BLXBgxnH4gA0zEd+t+BO2cNB8idaBtZFcFTRjQJRJmAw==",
- "hasInstallScript": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
- "node_modules/core-js-pure": {
- "version": "3.26.0",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.26.0.tgz",
- "integrity": "sha512-LiN6fylpVBVwT8twhhluD9TzXmZQQsr2I2eIKtWNbZI1XMfBT7CV18itaN6RA7EtQd/SDdRx/wzvAShX2HvhQA==",
- "dev": true,
- "hasInstallScript": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
- "node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/csstype": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz",
- "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw=="
- },
- "node_modules/d3-array": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz",
- "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==",
- "dependencies": {
- "internmap": "1 - 2"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-color": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
- "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-ease": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz",
- "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-format": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz",
- "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-interpolate": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
- "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
- "dependencies": {
- "d3-color": "1 - 3"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-path": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz",
- "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-scale": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz",
- "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==",
- "dependencies": {
- "d3-array": "2.10.0 - 3",
- "d3-format": "1 - 3",
- "d3-interpolate": "1.2.0 - 3",
- "d3-time": "2.1.1 - 3",
- "d3-time-format": "2 - 4"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-shape": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.1.0.tgz",
- "integrity": "sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==",
- "dependencies": {
- "d3-path": "1 - 3"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-time": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz",
- "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==",
- "dependencies": {
- "d3-array": "2 - 3"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-time-format": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz",
- "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==",
- "dependencies": {
- "d3-time": "1 - 3"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/d3-timer": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz",
- "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/damerau-levenshtein": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
- "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
- "dev": true
- },
- "node_modules/debug": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
- "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
- "dev": true,
- "dependencies": {
- "ms": "2.1.2"
- },
- "engines": {
- "node": ">=6.0"
- },
- "peerDependenciesMeta": {
- "supports-color": {
- "optional": true
- }
- }
- },
- "node_modules/decimal.js": {
- "version": "10.4.3",
- "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
- "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
- },
- "node_modules/deep-diff": {
- "version": "0.3.8",
- "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz",
- "integrity": "sha512-yVn6RZmHiGnxRKR9sJb3iVV2XTF1Ghh2DiWRZ3dMnGc43yUdWWF/kX6lQyk3+P84iprfWKU/8zFTrlkvtFm1ug=="
- },
- "node_modules/deep-is": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
- "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
- "dev": true
- },
- "node_modules/define-lazy-prop": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
- "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/define-properties": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz",
- "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==",
- "dev": true,
- "dependencies": {
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/delaunator": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-4.0.1.tgz",
- "integrity": "sha512-WNPWi1IRKZfCt/qIDMfERkDp93+iZEmOxN2yy4Jg+Xhv8SLk2UTqqbe1sfiipn0and9QrE914/ihdx82Y/Giag=="
- },
- "node_modules/delaunay-find": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/delaunay-find/-/delaunay-find-0.0.6.tgz",
- "integrity": "sha512-1+almjfrnR7ZamBk0q3Nhg6lqSe6Le4vL0WJDSMx4IDbQwTpUTXPjxC00lqLBT8MYsJpPCbI16sIkw9cPsbi7Q==",
- "dependencies": {
- "delaunator": "^4.0.0"
- }
- },
- "node_modules/detect-node": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
- "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="
- },
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/emoji-regex": {
- "version": "9.2.2",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
- "dev": true
- },
- "node_modules/enhanced-resolve": {
- "version": "5.12.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
- "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/es-abstract": {
- "version": "1.20.4",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz",
- "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "es-to-primitive": "^1.2.1",
- "function-bind": "^1.1.1",
- "function.prototype.name": "^1.1.5",
- "get-intrinsic": "^1.1.3",
- "get-symbol-description": "^1.0.0",
- "has": "^1.0.3",
- "has-property-descriptors": "^1.0.0",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "is-callable": "^1.2.7",
- "is-negative-zero": "^2.0.2",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "is-string": "^1.0.7",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.12.2",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.4.3",
- "safe-regex-test": "^1.0.0",
- "string.prototype.trimend": "^1.0.5",
- "string.prototype.trimstart": "^1.0.5",
- "unbox-primitive": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-cookie": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz",
- "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q=="
- },
- "node_modules/es-shim-unscopables": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
- "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
- "dev": true,
- "dependencies": {
- "has": "^1.0.3"
- }
- },
- "node_modules/es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
- "dev": true,
- "dependencies": {
- "is-callable": "^1.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/escape-latex": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz",
- "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw=="
- },
- "node_modules/escape-string-regexp": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
- "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint": {
- "version": "8.36.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.36.0.tgz",
- "integrity": "sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw==",
- "dev": true,
- "dependencies": {
- "@eslint-community/eslint-utils": "^4.2.0",
- "@eslint-community/regexpp": "^4.4.0",
- "@eslint/eslintrc": "^2.0.1",
- "@eslint/js": "8.36.0",
- "@humanwhocodes/config-array": "^0.11.8",
- "@humanwhocodes/module-importer": "^1.0.1",
- "@nodelib/fs.walk": "^1.2.8",
- "ajv": "^6.10.0",
- "chalk": "^4.0.0",
- "cross-spawn": "^7.0.2",
- "debug": "^4.3.2",
- "doctrine": "^3.0.0",
- "escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.1.1",
- "eslint-visitor-keys": "^3.3.0",
- "espree": "^9.5.0",
- "esquery": "^1.4.2",
- "esutils": "^2.0.2",
- "fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
- "find-up": "^5.0.0",
- "glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "grapheme-splitter": "^1.0.4",
- "ignore": "^5.2.0",
- "import-fresh": "^3.0.0",
- "imurmurhash": "^0.1.4",
- "is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-sdsl": "^4.1.4",
- "js-yaml": "^4.1.0",
- "json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
- "lodash.merge": "^4.6.2",
- "minimatch": "^3.1.2",
- "natural-compare": "^1.4.0",
- "optionator": "^0.9.1",
- "strip-ansi": "^6.0.1",
- "strip-json-comments": "^3.1.0",
- "text-table": "^0.2.0"
- },
- "bin": {
- "eslint": "bin/eslint.js"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/eslint-config-next": {
- "version": "13.2.4",
- "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-13.2.4.tgz",
- "integrity": "sha512-lunIBhsoeqw6/Lfkd6zPt25w1bn0znLA/JCL+au1HoEpSb4/PpsOYsYtgV/q+YPsoKIOzFyU5xnb04iZnXjUvg==",
- "dev": true,
- "dependencies": {
- "@next/eslint-plugin-next": "13.2.4",
- "@rushstack/eslint-patch": "^1.1.3",
- "@typescript-eslint/parser": "^5.42.0",
- "eslint-import-resolver-node": "^0.3.6",
- "eslint-import-resolver-typescript": "^3.5.2",
- "eslint-plugin-import": "^2.26.0",
- "eslint-plugin-jsx-a11y": "^6.5.1",
- "eslint-plugin-react": "^7.31.7",
- "eslint-plugin-react-hooks": "^4.5.0"
- },
- "peerDependencies": {
- "eslint": "^7.23.0 || ^8.0.0",
- "typescript": ">=3.3.1"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-import-resolver-node": {
- "version": "0.3.7",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz",
- "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==",
- "dev": true,
- "dependencies": {
- "debug": "^3.2.7",
- "is-core-module": "^2.11.0",
- "resolve": "^1.22.1"
- }
- },
- "node_modules/eslint-import-resolver-node/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-import-resolver-typescript": {
- "version": "3.5.3",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz",
- "integrity": "sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==",
- "dev": true,
- "dependencies": {
- "debug": "^4.3.4",
- "enhanced-resolve": "^5.10.0",
- "get-tsconfig": "^4.2.0",
- "globby": "^13.1.2",
- "is-core-module": "^2.10.0",
- "is-glob": "^4.0.3",
- "synckit": "^0.8.4"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts"
- },
- "peerDependencies": {
- "eslint": "*",
- "eslint-plugin-import": "*"
- }
- },
- "node_modules/eslint-import-resolver-typescript/node_modules/globby": {
- "version": "13.1.3",
- "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz",
- "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==",
- "dev": true,
- "dependencies": {
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.11",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint-import-resolver-typescript/node_modules/slash": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
- "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/eslint-module-utils": {
- "version": "2.7.4",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz",
- "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==",
- "dev": true,
- "dependencies": {
- "debug": "^3.2.7"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependenciesMeta": {
- "eslint": {
- "optional": true
- }
- }
- },
- "node_modules/eslint-module-utils/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-import": {
- "version": "2.27.5",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz",
- "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==",
- "dev": true,
- "dependencies": {
- "array-includes": "^3.1.6",
- "array.prototype.flat": "^1.3.1",
- "array.prototype.flatmap": "^1.3.1",
- "debug": "^3.2.7",
- "doctrine": "^2.1.0",
- "eslint-import-resolver-node": "^0.3.7",
- "eslint-module-utils": "^2.7.4",
- "has": "^1.0.3",
- "is-core-module": "^2.11.0",
- "is-glob": "^4.0.3",
- "minimatch": "^3.1.2",
- "object.values": "^1.1.6",
- "resolve": "^1.22.1",
- "semver": "^6.3.0",
- "tsconfig-paths": "^3.14.1"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/debug": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
- "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
- "dev": true,
- "dependencies": {
- "ms": "^2.1.1"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-import/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/eslint-plugin-jsx-a11y": {
- "version": "6.6.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz",
- "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.18.9",
- "aria-query": "^4.2.2",
- "array-includes": "^3.1.5",
- "ast-types-flow": "^0.0.7",
- "axe-core": "^4.4.3",
- "axobject-query": "^2.2.0",
- "damerau-levenshtein": "^1.0.8",
- "emoji-regex": "^9.2.2",
- "has": "^1.0.3",
- "jsx-ast-utils": "^3.3.2",
- "language-tags": "^1.0.5",
- "minimatch": "^3.1.2",
- "semver": "^6.3.0"
- },
- "engines": {
- "node": ">=4.0"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
- }
- },
- "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/eslint-plugin-react": {
- "version": "7.31.10",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz",
- "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==",
- "dev": true,
- "dependencies": {
- "array-includes": "^3.1.5",
- "array.prototype.flatmap": "^1.3.0",
- "doctrine": "^2.1.0",
- "estraverse": "^5.3.0",
- "jsx-ast-utils": "^2.4.1 || ^3.0.0",
- "minimatch": "^3.1.2",
- "object.entries": "^1.1.5",
- "object.fromentries": "^2.0.5",
- "object.hasown": "^1.1.1",
- "object.values": "^1.1.5",
- "prop-types": "^15.8.1",
- "resolve": "^2.0.0-next.3",
- "semver": "^6.3.0",
- "string.prototype.matchall": "^4.0.7"
- },
- "engines": {
- "node": ">=4"
- },
- "peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
- }
- },
- "node_modules/eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/resolve": {
- "version": "2.0.0-next.4",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz",
- "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/semver": {
- "version": "6.3.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
- "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
- "dev": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/eslint-scope": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
- "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
- "dev": true,
- "dependencies": {
- "esrecurse": "^4.3.0",
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/eslint-visitor-keys": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
- "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/espree": {
- "version": "9.5.0",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.0.tgz",
- "integrity": "sha512-JPbJGhKc47++oo4JkEoTe2wjy4fmMwvFpgJT9cQzmfXKp22Dr6Hf1tdCteLz1h0P3t+mGvWZ+4Uankvh8+c6zw==",
- "dev": true,
- "dependencies": {
- "acorn": "^8.8.0",
- "acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/eslint"
- }
- },
- "node_modules/esquery": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
- "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.1.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/esrecurse": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
- "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
- "dev": true,
- "dependencies": {
- "estraverse": "^5.2.0"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/estraverse": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
- "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
- "dev": true,
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/fast-deep-equal": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
- "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true
- },
- "node_modules/fast-glob": {
- "version": "3.2.12",
- "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
- "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
- "dev": true,
- "dependencies": {
- "@nodelib/fs.stat": "^2.0.2",
- "@nodelib/fs.walk": "^1.2.3",
- "glob-parent": "^5.1.2",
- "merge2": "^1.3.0",
- "micromatch": "^4.0.4"
- },
- "engines": {
- "node": ">=8.6.0"
- }
- },
- "node_modules/fast-glob/node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/fast-json-stable-stringify": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
- "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
- "dev": true
- },
- "node_modules/fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
- "dev": true
- },
- "node_modules/fast-text-encoding": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz",
- "integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
- },
- "node_modules/fastq": {
- "version": "1.13.0",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
- "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
- "dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
- "dev": true,
- "dependencies": {
- "flat-cache": "^3.0.4"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/file-saver": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-1.3.8.tgz",
- "integrity": "sha512-spKHSBQIxxS81N/O21WmuXA2F6wppUCsutpzenOeZzOCCJ5gEfcbqJP983IrpLXzYmXnMUa6J03SubcNPdKrlg=="
- },
- "node_modules/file-selector": {
- "version": "0.1.19",
- "resolved": "https://registry.npmjs.org/file-selector/-/file-selector-0.1.19.tgz",
- "integrity": "sha512-kCWw3+Aai8Uox+5tHCNgMFaUdgidxvMnLWO6fM5sZ0hA2wlHP5/DHGF0ECe84BiB95qdJbKNEJhWKVDvMN+JDQ==",
- "dependencies": {
- "tslib": "^2.0.1"
- },
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/fill-range": {
- "version": "7.0.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
- "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/find-up": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
- "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
- "dev": true,
- "dependencies": {
- "locate-path": "^6.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/flat-cache": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
- "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
- "dev": true,
- "dependencies": {
- "flatted": "^3.1.0",
- "rimraf": "^3.0.2"
- },
- "engines": {
- "node": "^10.12.0 || >=12.0.0"
- }
- },
- "node_modules/flatted": {
- "version": "3.2.7",
- "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
- "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
- "dev": true
- },
- "node_modules/focus-trap": {
- "version": "6.9.2",
- "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-6.9.2.tgz",
- "integrity": "sha512-gBEuXOPNOKPrLdZpMFUSTyIo1eT2NSZRrwZ9r/0Jqw5tmT3Yvxfmu8KBHw8xW2XQkw6E/JoG+OlEq7UDtSUNgw==",
- "dependencies": {
- "tabbable": "^5.3.2"
- }
- },
- "node_modules/fraction.js": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
- "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
- "engines": {
- "node": "*"
- },
- "funding": {
- "type": "patreon",
- "url": "https://www.patreon.com/infusion"
- }
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
- },
- "node_modules/function-bind": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
- "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
- "dev": true
- },
- "node_modules/function.prototype.name": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
- "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.0",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
- "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1",
- "has": "^1.0.3",
- "has-symbols": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-symbol-description": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
- "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-tsconfig": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.4.0.tgz",
- "integrity": "sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
- }
- },
- "node_modules/glob": {
- "version": "7.1.7",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
- "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.0.4",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/glob-to-regexp": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
- "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
- },
- "node_modules/globals": {
- "version": "13.20.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
- "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
- "dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/globalyzer": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz",
- "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==",
- "dev": true
- },
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/globrex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz",
- "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==",
- "dev": true
- },
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
- },
- "node_modules/grapheme-splitter": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
- "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
- "dev": true
- },
- "node_modules/has": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
- "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
- "dev": true,
- "dependencies": {
- "function-bind": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/has-property-descriptors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
- "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.1.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
- "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
- "dev": true,
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hoist-non-react-statics": {
- "version": "3.3.2",
- "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
- "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
- "dependencies": {
- "react-is": "^16.7.0"
- }
- },
- "node_modules/ignore": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
- "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
- "dev": true,
- "engines": {
- "node": ">= 4"
- }
- },
- "node_modules/immer": {
- "version": "9.0.21",
- "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
- "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/immer"
- }
- },
- "node_modules/import-fresh": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
- "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
- "dev": true,
- "dependencies": {
- "parent-module": "^1.0.0",
- "resolve-from": "^4.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
- "dev": true,
- "engines": {
- "node": ">=0.8.19"
- }
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
- },
- "node_modules/internal-slot": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
- "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.1.0",
- "has": "^1.0.3",
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/internmap": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz",
- "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==",
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "dev": true,
- "dependencies": {
- "has-bigints": "^1.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.11.0",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
- "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
- "dev": true,
- "dependencies": {
- "has": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-docker": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
- "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
- "dev": true,
- "bin": {
- "is-docker": "cli.js"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-negative-zero": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
- "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
- "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dev": true,
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "dev": true,
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-wsl": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
- "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
- "dev": true,
- "dependencies": {
- "is-docker": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/its-fine": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.0.6.tgz",
- "integrity": "sha512-VZJZPwVT2kxe5KQv+TxCjojfLiUIut8zXDNLTxcM7gJ/xQ/bSPk5M0neZ+j3myy45KKkltY1mm1jyJgx3Fxsdg==",
- "dependencies": {
- "@types/react-reconciler": "^0.28.0"
- },
- "peerDependencies": {
- "react": ">=18.0"
- }
- },
- "node_modules/javascript-natural-sort": {
- "version": "0.7.1",
- "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz",
- "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw=="
- },
- "node_modules/js-sdsl": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
- "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==",
- "dev": true
- },
- "node_modules/js-sha3": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz",
- "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q=="
- },
- "node_modules/js-tokens": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
- "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
- },
- "node_modules/js-yaml": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
- "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
- "dev": true,
- "dependencies": {
- "argparse": "^2.0.1"
- },
- "bin": {
- "js-yaml": "bin/js-yaml.js"
- }
- },
- "node_modules/json-schema-traverse": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
- "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
- "dev": true
- },
- "node_modules/json-stable-stringify-without-jsonify": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
- "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
- "dev": true
- },
- "node_modules/json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
- },
- "node_modules/json5": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
- "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
- "dev": true,
- "dependencies": {
- "minimist": "^1.2.0"
- },
- "bin": {
- "json5": "lib/cli.js"
- }
- },
- "node_modules/jsx-ast-utils": {
- "version": "3.3.3",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz",
- "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==",
- "dev": true,
- "dependencies": {
- "array-includes": "^3.1.5",
- "object.assign": "^4.1.3"
- },
- "engines": {
- "node": ">=4.0"
- }
- },
- "node_modules/konva": {
- "version": "8.4.3",
- "resolved": "https://registry.npmjs.org/konva/-/konva-8.4.3.tgz",
- "integrity": "sha512-ARqdgAbdNIougRlOKvkQwHlGhXPRBV4KvhCP+qoPpGoVQwwiJe4Hkdu4HHdRPb9rGUp04jDTAxBzEwBsE272pg==",
- "funding": [
- {
- "type": "patreon",
- "url": "https://www.patreon.com/lavrton"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/konva"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/lavrton"
- }
- ]
- },
- "node_modules/language-subtag-registry": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
- "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
- "dev": true
- },
- "node_modules/language-tags": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz",
- "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==",
- "dev": true,
- "dependencies": {
- "language-subtag-registry": "~0.3.2"
- }
- },
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/locate-path": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
- "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
- "dev": true,
- "dependencies": {
- "p-locate": "^5.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
- },
- "node_modules/lodash.merge": {
- "version": "4.6.2",
- "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
- "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
- "dev": true
- },
- "node_modules/loose-envify": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
- "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
- "dependencies": {
- "js-tokens": "^3.0.0 || ^4.0.0"
- },
- "bin": {
- "loose-envify": "cli.js"
- }
- },
- "node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/match-sorter": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/match-sorter/-/match-sorter-6.3.1.tgz",
- "integrity": "sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==",
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "remove-accents": "0.4.2"
- }
- },
- "node_modules/mathjs": {
- "version": "11.7.0",
- "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-11.7.0.tgz",
- "integrity": "sha512-RCXtrP5xGIbl9PUc5+7QL81rBCUjzoIZ0ugNqKsarOUxg+x7deY0BzfNai+bGfUL/T+1uYq1xs5w2xVdL3lp0g==",
- "dependencies": {
- "@babel/runtime": "^7.21.0",
- "complex.js": "^2.1.1",
- "decimal.js": "^10.4.3",
- "escape-latex": "^1.2.0",
- "fraction.js": "^4.2.0",
- "javascript-natural-sort": "^0.7.1",
- "seedrandom": "^3.0.5",
- "tiny-emitter": "^2.1.0",
- "typed-function": "^4.1.0"
- },
- "bin": {
- "mathjs": "bin/cli.js"
- },
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/merge2": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
- "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
- "dev": true,
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
- "dev": true,
- "dependencies": {
- "braces": "^3.0.2",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/microseconds": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/microseconds/-/microseconds-0.2.0.tgz",
- "integrity": "sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA=="
- },
- "node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/ms": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
- "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
- "dev": true
- },
- "node_modules/nano-time": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/nano-time/-/nano-time-1.0.0.tgz",
- "integrity": "sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==",
- "dependencies": {
- "big-integer": "^1.6.16"
- }
- },
- "node_modules/nanoid": {
- "version": "3.3.6",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
- "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "bin": {
- "nanoid": "bin/nanoid.cjs"
- },
- "engines": {
- "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
- }
- },
- "node_modules/natural-compare": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
- "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
- "dev": true
- },
- "node_modules/next": {
- "version": "13.5.4",
- "resolved": "https://registry.npmjs.org/next/-/next-13.5.4.tgz",
- "integrity": "sha512-+93un5S779gho8y9ASQhb/bTkQF17FNQOtXLKAj3lsNgltEcF0C5PMLLncDmH+8X1EnJH1kbqAERa29nRXqhjA==",
- "dependencies": {
- "@next/env": "13.5.4",
- "@swc/helpers": "0.5.2",
- "busboy": "1.6.0",
- "caniuse-lite": "^1.0.30001406",
- "postcss": "8.4.31",
- "styled-jsx": "5.1.1",
- "watchpack": "2.4.0"
- },
- "bin": {
- "next": "dist/bin/next"
- },
- "engines": {
- "node": ">=16.14.0"
- },
- "optionalDependencies": {
- "@next/swc-darwin-arm64": "13.5.4",
- "@next/swc-darwin-x64": "13.5.4",
- "@next/swc-linux-arm64-gnu": "13.5.4",
- "@next/swc-linux-arm64-musl": "13.5.4",
- "@next/swc-linux-x64-gnu": "13.5.4",
- "@next/swc-linux-x64-musl": "13.5.4",
- "@next/swc-win32-arm64-msvc": "13.5.4",
- "@next/swc-win32-ia32-msvc": "13.5.4",
- "@next/swc-win32-x64-msvc": "13.5.4"
- },
- "peerDependencies": {
- "@opentelemetry/api": "^1.1.0",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "sass": "^1.3.0"
- },
- "peerDependenciesMeta": {
- "@opentelemetry/api": {
- "optional": true
- },
- "sass": {
- "optional": true
- }
- }
- },
- "node_modules/next-global-css": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/next-global-css/-/next-global-css-1.3.1.tgz",
- "integrity": "sha512-+OnTwQKmv1lDP7r4R3T94oq6372R9UGVivchBQu49j7ZjzvSXHCnv93yAuhgMkvUgAbGifTs8sQ5YL9wjyAxfA=="
- },
- "node_modules/normalizr": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/normalizr/-/normalizr-3.6.2.tgz",
- "integrity": "sha512-30qCybsBaCBciotorvuOZTCGEg2AXrJfADMT2Kk/lvpIAcipHdK0zc33nNtwKzyfQAqIJXAcqET6YgflYUgsoQ=="
- },
- "node_modules/object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.12.2",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
- "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.assign": {
- "version": "4.1.4",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
- "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.entries": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
- "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.fromentries": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz",
- "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.hasown": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz",
- "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==",
- "dev": true,
- "dependencies": {
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.values": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
- "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.20.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/oblivious-set": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/oblivious-set/-/oblivious-set-1.0.0.tgz",
- "integrity": "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw=="
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/open": {
- "version": "8.4.2",
- "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
- "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
- "dev": true,
- "dependencies": {
- "define-lazy-prop": "^2.0.0",
- "is-docker": "^2.1.1",
- "is-wsl": "^2.2.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/optionator": {
- "version": "0.9.1",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
- "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
- "dev": true,
- "dependencies": {
- "deep-is": "^0.1.3",
- "fast-levenshtein": "^2.0.6",
- "levn": "^0.4.1",
- "prelude-ls": "^1.2.1",
- "type-check": "^0.4.0",
- "word-wrap": "^1.2.3"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/p-limit": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
- "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
- "dev": true,
- "dependencies": {
- "yocto-queue": "^0.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/p-locate": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
- "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
- "dev": true,
- "dependencies": {
- "p-limit": "^3.0.2"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/parent-module": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
- "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
- "dev": true,
- "dependencies": {
- "callsites": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/path-exists": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
- "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "node_modules/path-type": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
- "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/popper.js": {
- "version": "1.16.1",
- "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
- "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==",
- "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/popperjs"
- }
- },
- "node_modules/postcss": {
- "version": "8.4.31",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
- "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
- "funding": [
- {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
- {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/postcss"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/ai"
- }
- ],
- "dependencies": {
- "nanoid": "^3.3.6",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
- },
- "engines": {
- "node": "^10 || ^12 || >=14"
- }
- },
- "node_modules/prelude-ls": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
- "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
- "dev": true,
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/prettier": {
- "version": "2.8.7",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz",
- "integrity": "sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==",
- "bin": {
- "prettier": "bin-prettier.js"
- },
- "engines": {
- "node": ">=10.13.0"
- },
- "funding": {
- "url": "https://github.com/prettier/prettier?sponsor=1"
- }
- },
- "node_modules/promise-polyfill": {
- "version": "8.3.0",
- "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz",
- "integrity": "sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg=="
- },
- "node_modules/prop-types": {
- "version": "15.8.1",
- "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
- "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dependencies": {
- "loose-envify": "^1.4.0",
- "object-assign": "^4.1.1",
- "react-is": "^16.13.1"
- }
- },
- "node_modules/prop-types-extra": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz",
- "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==",
- "dependencies": {
- "react-is": "^16.3.2",
- "warning": "^4.0.0"
- },
- "peerDependencies": {
- "react": ">=0.14.0"
- }
- },
- "node_modules/punycode": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
- "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/queue-microtask": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
- "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/react": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
- "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/react-dom": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
- "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
- },
- "peerDependencies": {
- "react": "^18.2.0"
- }
- },
- "node_modules/react-dropzone": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/react-dropzone/-/react-dropzone-9.0.0.tgz",
- "integrity": "sha512-wZ2o9B2qkdE3RumWhfyZT9swgJYJPeU5qHEcMU8weYpmLex1eeWX0CC32/Y0VutB+BBi2D+iePV/YZIiB4kZGw==",
- "dependencies": {
- "attr-accept": "^1.1.3",
- "file-selector": "^0.1.8",
- "prop-types": "^15.6.2",
- "prop-types-extra": "^1.1.0"
- },
- "engines": {
- "node": ">= 6"
- },
- "peerDependencies": {
- "react": ">=0.14.0"
- }
- },
- "node_modules/react-fast-compare": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz",
- "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
- },
- "node_modules/react-hotkeys-hook": {
- "version": "4.3.8",
- "resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-4.3.8.tgz",
- "integrity": "sha512-RmrIQ3M259c84MnYVEAQsmHkD6s7XUgLG0rW6S7qjt1Lh7q+SPIz5b6obVU8OJw1Utsj1mUCj6twtBPaK/ytww==",
- "peerDependencies": {
- "react": ">=16.8.1",
- "react-dom": ">=16.8.1"
- }
- },
- "node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
- },
- "node_modules/react-konva": {
- "version": "18.2.5",
- "resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.5.tgz",
- "integrity": "sha512-lTqJStcHnpGSXB9RlV7p5at3MpRML/TujzbuUDZRIInsLocJ/I4Nhhg3w6yJm9UV05kcwr88OY6LO+2zRyzXog==",
- "funding": [
- {
- "type": "patreon",
- "url": "https://www.patreon.com/lavrton"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/konva"
- },
- {
- "type": "github",
- "url": "https://github.com/sponsors/lavrton"
- }
- ],
- "dependencies": {
- "@types/react-reconciler": "^0.28.2",
- "its-fine": "^1.0.6",
- "react-reconciler": "~0.29.0",
- "scheduler": "^0.23.0"
- },
- "peerDependencies": {
- "konva": "^8.0.1 || ^7.2.5",
- "react": ">=18.0.0",
- "react-dom": ">=18.0.0"
- }
- },
- "node_modules/react-query": {
- "version": "3.39.3",
- "resolved": "https://registry.npmjs.org/react-query/-/react-query-3.39.3.tgz",
- "integrity": "sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==",
- "dependencies": {
- "@babel/runtime": "^7.5.5",
- "broadcast-channel": "^3.4.1",
- "match-sorter": "^6.0.2"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/tannerlinsley"
- },
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "react-dom": {
- "optional": true
- },
- "react-native": {
- "optional": true
- }
- }
- },
- "node_modules/react-reconciler": {
- "version": "0.29.0",
- "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz",
- "integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==",
- "dependencies": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.0"
- },
- "engines": {
- "node": ">=0.10.0"
- },
- "peerDependencies": {
- "react": "^18.2.0"
- }
- },
- "node_modules/react-redux": {
- "version": "8.0.5",
- "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.0.5.tgz",
- "integrity": "sha512-Q2f6fCKxPFpkXt1qNRZdEDLlScsDWyrgSj0mliK59qU6W5gvBiKkdMEG2lJzhd1rCctf0hb6EtePPLZ2e0m1uw==",
- "dependencies": {
- "@babel/runtime": "^7.12.1",
- "@types/hoist-non-react-statics": "^3.3.1",
- "@types/use-sync-external-store": "^0.0.3",
- "hoist-non-react-statics": "^3.3.2",
- "react-is": "^18.0.0",
- "use-sync-external-store": "^1.0.0"
- },
- "peerDependencies": {
- "@types/react": "^16.8 || ^17.0 || ^18.0",
- "@types/react-dom": "^16.8 || ^17.0 || ^18.0",
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0",
- "react-native": ">=0.59",
- "redux": "^4"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- },
- "react-dom": {
- "optional": true
- },
- "react-native": {
- "optional": true
- },
- "redux": {
- "optional": true
- }
- }
- },
- "node_modules/react-redux/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
- },
- "node_modules/redux": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
- "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
- "dependencies": {
- "@babel/runtime": "^7.9.2"
- }
- },
- "node_modules/redux-logger": {
- "version": "3.0.6",
- "resolved": "https://registry.npmjs.org/redux-logger/-/redux-logger-3.0.6.tgz",
- "integrity": "sha512-JoCIok7bg/XpqA1JqCqXFypuqBbQzGQySrhFzewB7ThcnysTO30l4VCst86AuB9T9tuT03MAA56Jw2PNhRSNCg==",
- "dependencies": {
- "deep-diff": "^0.3.5"
- }
- },
- "node_modules/redux-saga": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.2.3.tgz",
- "integrity": "sha512-HDe0wTR5nhd8Xr5xjGzoyTbdAw6rjy1GDplFt3JKtKN8/MnkQSRqK/n6aQQhpw5NI4ekDVOaW+w4sdxPBaCoTQ==",
- "dependencies": {
- "@redux-saga/core": "^1.2.3"
- }
- },
- "node_modules/redux-thunk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.2.tgz",
- "integrity": "sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==",
- "peerDependencies": {
- "redux": "^4"
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
- },
- "node_modules/regexp.prototype.flags": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz",
- "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "functions-have-names": "^1.2.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/remove-accents": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.4.2.tgz",
- "integrity": "sha512-7pXIJqJOq5tFgG1A2Zxti3Ht8jJF337m4sowbuHsW30ZnkQFnDzy9qBNhgzX8ZLW4+UBcXiiR7SwR6pokHsxiA=="
- },
- "node_modules/resolve": {
- "version": "1.22.1",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
- "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.9.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-from": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
- "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/run-parallel": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
- "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "queue-microtask": "^1.2.2"
- }
- },
- "node_modules/safe-regex-test": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
- "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "is-regex": "^1.1.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/scheduler": {
- "version": "0.23.0",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
- "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- }
- },
- "node_modules/seedrandom": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
- "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
- },
- "node_modules/semver": {
- "version": "7.3.8",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
- "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
- "bin": {
- "semver": "bin/semver.js"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/side-channel": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
- "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.0",
- "get-intrinsic": "^1.0.2",
- "object-inspect": "^1.9.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/streamsearch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
- "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/string.prototype.matchall": {
- "version": "4.0.7",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz",
- "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.3",
- "es-abstract": "^1.19.1",
- "get-intrinsic": "^1.1.1",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.3",
- "regexp.prototype.flags": "^1.4.1",
- "side-channel": "^1.0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimend": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
- "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/string.prototype.trimstart": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
- "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.1.4",
- "es-abstract": "^1.19.5"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/strip-bom": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
- "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/strip-json-comments": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
- "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/styled-jsx": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
- "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
- "dependencies": {
- "client-only": "0.0.1"
- },
- "engines": {
- "node": ">= 12.0.0"
- },
- "peerDependencies": {
- "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
- },
- "peerDependenciesMeta": {
- "@babel/core": {
- "optional": true
- },
- "babel-plugin-macros": {
- "optional": true
- }
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/svgsaver": {
- "version": "0.9.0",
- "resolved": "https://registry.npmjs.org/svgsaver/-/svgsaver-0.9.0.tgz",
- "integrity": "sha512-m94bg62CjuKyhcyJV50ljIPDo5FxEwmdOn60IvHEPlGKhC8gNMnyxbjlYmGi9QW9rIi93DjvfjBuafFfn3+m0w==",
- "dependencies": {
- "computed-styles": "^1.1.2",
- "file-saver": "^1.3.3"
- }
- },
- "node_modules/synckit": {
- "version": "0.8.5",
- "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
- "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
- "dev": true,
- "dependencies": {
- "@pkgr/utils": "^2.3.1",
- "tslib": "^2.5.0"
- },
- "engines": {
- "node": "^14.18.0 || >=16.0.0"
- },
- "funding": {
- "url": "https://opencollective.com/unts"
- }
- },
- "node_modules/tabbable": {
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-5.3.3.tgz",
- "integrity": "sha512-QD9qKY3StfbZqWOPLp0++pOrAVb/HbUi5xCc8cUo4XjP19808oaMiDzn0leBY5mCespIBM0CIZePzZjgzR83kA=="
- },
- "node_modules/tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
- "dev": true
- },
- "node_modules/tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
- },
- "node_modules/tiny-glob": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
- "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==",
- "dev": true,
- "dependencies": {
- "globalyzer": "0.1.0",
- "globrex": "^0.1.2"
- }
- },
- "node_modules/tippy.js": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-5.1.2.tgz",
- "integrity": "sha512-Qtrv2wqbRbaKMUb6bWWBQWPayvcDKNrGlvihxtsyowhT7RLGEh1STWuy6EMXC6QLkfKPB2MLnf8W2mzql9VDAw==",
- "dependencies": {
- "popper.js": "^1.16.0"
- }
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/tsconfig-paths": {
- "version": "3.14.2",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
- "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
- "dev": true,
- "dependencies": {
- "@types/json5": "^0.0.29",
- "json5": "^1.0.2",
- "minimist": "^1.2.6",
- "strip-bom": "^3.0.0"
- }
- },
- "node_modules/tslib": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
- "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
- },
- "node_modules/tsutils": {
- "version": "3.21.0",
- "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
- "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
- "dev": true,
- "dependencies": {
- "tslib": "^1.8.1"
- },
- "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"
- }
- },
- "node_modules/tsutils/node_modules/tslib": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
- "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
- "dev": true
- },
- "node_modules/type-check": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
- "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
- "dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.8.0"
- }
- },
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/typed-function": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.1.0.tgz",
- "integrity": "sha512-DGwUl6cioBW5gw2L+6SMupGwH/kZOqivy17E4nsh1JI9fKF87orMmlQx3KISQPmg3sfnOUGlwVkroosvgddrlg==",
- "engines": {
- "node": ">= 14"
- }
- },
- "node_modules/typescript": {
- "version": "5.4.5",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz",
- "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==",
- "dev": true,
- "peer": true,
- "bin": {
- "tsc": "bin/tsc",
- "tsserver": "bin/tsserver"
- },
- "engines": {
- "node": ">=14.17"
- }
- },
- "node_modules/typescript-compare": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
- "integrity": "sha512-8ja4j7pMHkfLJQO2/8tut7ub+J3Lw2S3061eJLFQcvs3tsmJKp8KG5NtpLn7KcY2w08edF74BSVN7qJS0U6oHA==",
- "dependencies": {
- "typescript-logic": "^0.0.0"
- }
- },
- "node_modules/typescript-logic": {
- "version": "0.0.0",
- "resolved": "https://registry.npmjs.org/typescript-logic/-/typescript-logic-0.0.0.tgz",
- "integrity": "sha512-zXFars5LUkI3zP492ls0VskH3TtdeHCqu0i7/duGt60i5IGPIpAHE/DWo5FqJ6EjQ15YKXrt+AETjv60Dat34Q=="
- },
- "node_modules/typescript-tuple": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/typescript-tuple/-/typescript-tuple-2.2.1.tgz",
- "integrity": "sha512-Zcr0lbt8z5ZdEzERHAMAniTiIKerFCMgd7yjq1fPnDJ43et/k9twIFQMUYff9k5oXcsQ0WpvFcgzK2ZKASoW6Q==",
- "dependencies": {
- "typescript-compare": "^0.0.2"
- }
- },
- "node_modules/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^1.0.2"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/unfetch": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.2.0.tgz",
- "integrity": "sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA=="
- },
- "node_modules/unload": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/unload/-/unload-2.2.0.tgz",
- "integrity": "sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==",
- "dependencies": {
- "@babel/runtime": "^7.6.2",
- "detect-node": "^2.0.4"
- }
- },
- "node_modules/uri-js": {
- "version": "4.4.1",
- "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
- "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
- "dev": true,
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
- "node_modules/use-resize-observer": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/use-resize-observer/-/use-resize-observer-9.1.0.tgz",
- "integrity": "sha512-R25VqO9Wb3asSD4eqtcxk8sJalvIOYBqS8MNZlpDSQ4l4xMQxC/J7Id9HoTqPq8FwULIn0PVW+OAqF2dyYbjow==",
- "dependencies": {
- "@juggle/resize-observer": "^3.3.1"
- },
- "peerDependencies": {
- "react": "16.8.0 - 18",
- "react-dom": "16.8.0 - 18"
- }
- },
- "node_modules/use-sync-external-store": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
- "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- }
- },
- "node_modules/uuid": {
- "version": "9.0.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
- "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
- "node_modules/victory-area": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-area/-/victory-area-36.6.8.tgz",
- "integrity": "sha512-aIyMuzUqiDcpTCB7FUOYDJvqiDPiluEXLOw6Lh1vrUYmV7CNqMDOIBtTau2vI41Ao0o0YJdCAcyzBib9e3UYbw==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8",
- "victory-vendor": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-axis": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-axis/-/victory-axis-36.6.8.tgz",
- "integrity": "sha512-tClVJEay1YOJAh9rRyyLx8pei7Sr1/xTz04bJmfzFoAxFoPBtvgfFwXhfZ1YjGIl7m5Wh2CiYMY3figueLzYtg==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-bar": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-bar/-/victory-bar-36.6.8.tgz",
- "integrity": "sha512-jLLPm3IW8/2uSLPvQD9bxzXnTraUYBIDTkbZPZy7oHP01OVzP1sj+MMHcINCWcUbyUyLZDL3u8CvViXjS273JQ==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8",
- "victory-vendor": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-brush-container": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-brush-container/-/victory-brush-container-36.6.8.tgz",
- "integrity": "sha512-PN5zQ6kjVwZca1qV41WlV6J2IEyQh+2hykRe6c/wERDotVVbSrX3sJVAzUbN+7x2rrK0CL6a/XUI8jDsWTMM2A==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "react-fast-compare": "^3.2.0",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-chart": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-chart/-/victory-chart-36.6.8.tgz",
- "integrity": "sha512-kC1jL63PAmqUrvZNOfwAXNuaIwz4nvXYUuEPu59WRBCOIGDGRgv2wJ1O7O0xYXqDkI57EtAYf9KUK+miEn/Btg==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "react-fast-compare": "^3.2.0",
- "victory-axis": "^36.6.8",
- "victory-core": "^36.6.8",
- "victory-polar-axis": "^36.6.8",
- "victory-shared-events": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-core": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-core/-/victory-core-36.6.8.tgz",
- "integrity": "sha512-SkyEszZKGyxjqfptfFWYdI22CvCuE9LhkaDpikzIhT2gcE3SuOBO5fk/740XMYE2ZUsJ4Fu/Vy4+8jZi17y44A==",
- "dependencies": {
- "lodash": "^4.17.21",
- "prop-types": "^15.8.1",
- "react-fast-compare": "^3.2.0",
- "victory-vendor": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-create-container": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-create-container/-/victory-create-container-36.6.8.tgz",
- "integrity": "sha512-H2BsdTbJ/RxxcEg5lzk3TDlihtOs7I/5KaIBP3yosPs702i40mL2qndkRkj08QeiZhkaKfQ2GOUvyP+t7DSdmg==",
- "dependencies": {
- "lodash": "^4.17.19",
- "victory-brush-container": "^36.6.8",
- "victory-core": "^36.6.8",
- "victory-cursor-container": "^36.6.8",
- "victory-selection-container": "^36.6.8",
- "victory-voronoi-container": "^36.6.8",
- "victory-zoom-container": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-cursor-container": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-cursor-container/-/victory-cursor-container-36.6.8.tgz",
- "integrity": "sha512-3WIBRl+7jnZok6syLfW8RK23nliDcoD/JUTN0YZo6bKBqHeFc4+ur3mlwCfghH7sGoxJRYuOJxTd9x2MwM5HQQ==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-errorbar": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-errorbar/-/victory-errorbar-36.6.8.tgz",
- "integrity": "sha512-N4JdBy5wV+KU6pus7FBx+5on31oXanO+qVmtRH8u4W7CMWH5EwHortyu2wVYD9K2QoluXemIxZd7kfn14hmqfQ==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-group": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-group/-/victory-group-36.6.8.tgz",
- "integrity": "sha512-CiupDIGPPWVgwif3ayd8glSlR41mVbuT0Nl0ay9q42w2fiM32syiJAoifIw47X4tL8ow/DXH+/5Pd8eEyA2trA==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "react-fast-compare": "^3.2.0",
- "victory-core": "^36.6.8",
- "victory-shared-events": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-legend": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-legend/-/victory-legend-36.6.8.tgz",
- "integrity": "sha512-OnkzB82Mvt5/1LYNsrfZQoXaVvgfp1rCsFRI3imq257Sh/UPy0/eZehCMQs/SVbU0z0EuIpXokhZb3BBdoJgpw==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-line": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-line/-/victory-line-36.6.8.tgz",
- "integrity": "sha512-MozOejQRZPdzFaru5zUfqVB4TEff6nZjtQhOs+F5yyhXjLgM89zGX30r3jK5cjVdAPbTu4KPUrwktvlw+AkPRA==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8",
- "victory-vendor": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-pie": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-pie/-/victory-pie-36.6.8.tgz",
- "integrity": "sha512-dUHWiiKd60dlt7OjFa+YYwanHAkP/T0abzy6O3SFxGre52oeqd8px1EoVhlLKpn4ao8L35koG9mvz6/pGyr8Dw==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8",
- "victory-vendor": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-polar-axis": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-polar-axis/-/victory-polar-axis-36.6.8.tgz",
- "integrity": "sha512-aU+Wp5six21POhI9oXeREnZHljpqcmwFHHnliVGrwgRsuc7TAjfXPWVOX9guEFfh6zQW6IZWWWTTLAN/PIEm9w==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-scatter": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-scatter/-/victory-scatter-36.6.8.tgz",
- "integrity": "sha512-GKSNneBxIWLsF3eBSTW5IwT5S4YdsfFl4PVCP3/wTa2myfS5DIS9FufEnJp/FEZGalEXYWxeR47rlWqABxAj5A==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-selection-container": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-selection-container/-/victory-selection-container-36.6.8.tgz",
- "integrity": "sha512-kudYbSX+o7fr64oeN7+EG/c+lqO22aypxVdCwa6BagAGoqqLR4jXxTqqIdp8tvxCgfCCXxopnTKYr46nubypGw==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-shared-events": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-shared-events/-/victory-shared-events-36.6.8.tgz",
- "integrity": "sha512-hWPOVqMD3Sv6Rl1iyO6ibQrwYF9/eLCnRo0T59/Hsid6On0AJJjL9gv0oEIM5fqz7R7zx9PJmMk877IctEOemw==",
- "dependencies": {
- "json-stringify-safe": "^5.0.1",
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "react-fast-compare": "^3.2.0",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-stack": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-stack/-/victory-stack-36.6.8.tgz",
- "integrity": "sha512-Pkux46IqAealOi0KvqQpaJKKKpHCfZ/sh5IeUKYFy+QKWAjiQjG6hFZeHgr2YaS7OfdbvHhoAdvp03KntWzpbw==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "react-fast-compare": "^3.2.0",
- "victory-core": "^36.6.8",
- "victory-shared-events": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-tooltip": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-tooltip/-/victory-tooltip-36.6.8.tgz",
- "integrity": "sha512-9P+QeAGyDpP0trJnQ1NtnbDhpoJB0Ghc2boYEehvL12p0OzolY9/Nq5SDP0tu5i1BBujwFXtnoCDqt+mOH25fA==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-vendor": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-36.6.8.tgz",
- "integrity": "sha512-H3kyQ+2zgjMPvbPqAl7Vwm2FD5dU7/4bCTQakFQnpIsfDljeOMDojRsrmJfwh4oAlNnWhpAf+mbAoLh8u7dwyQ==",
- "dependencies": {
- "@types/d3-array": "^3.0.3",
- "@types/d3-ease": "^3.0.0",
- "@types/d3-interpolate": "^3.0.1",
- "@types/d3-scale": "^4.0.2",
- "@types/d3-shape": "^3.1.0",
- "@types/d3-time": "^3.0.0",
- "@types/d3-timer": "^3.0.0",
- "d3-array": "^3.1.6",
- "d3-ease": "^3.0.1",
- "d3-interpolate": "^3.0.1",
- "d3-scale": "^4.0.2",
- "d3-shape": "^3.1.0",
- "d3-time": "^3.0.0",
- "d3-timer": "^3.0.1"
- }
- },
- "node_modules/victory-voronoi-container": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-voronoi-container/-/victory-voronoi-container-36.6.8.tgz",
- "integrity": "sha512-x9/OOZdMm4dh38jNhSfBYT0nG6ribsINU0/WNzIn3QcDXFBInsJ7jRySxYmdmk45OdXfbDRwDMqVHk72sWQyUw==",
- "dependencies": {
- "delaunay-find": "0.0.6",
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "react-fast-compare": "^3.2.0",
- "victory-core": "^36.6.8",
- "victory-tooltip": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/victory-zoom-container": {
- "version": "36.6.8",
- "resolved": "https://registry.npmjs.org/victory-zoom-container/-/victory-zoom-container-36.6.8.tgz",
- "integrity": "sha512-gxX5iJUaxrFFZ2IGS0sQnUI+3Mhj6bVLqtOlQd3Krld+9f/ieuUbxl+P+eIyhQU/VyHSlirIZeOGOXJeYcU9jQ==",
- "dependencies": {
- "lodash": "^4.17.19",
- "prop-types": "^15.8.1",
- "victory-core": "^36.6.8"
- },
- "peerDependencies": {
- "react": ">=16.6.0"
- }
- },
- "node_modules/warning": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
- "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
- "dependencies": {
- "loose-envify": "^1.0.0"
- }
- },
- "node_modules/watchpack": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
- "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
- "dependencies": {
- "glob-to-regexp": "^0.4.1",
- "graceful-fs": "^4.1.2"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/which": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
- "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "node-which": "bin/node-which"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
- "dev": true,
- "dependencies": {
- "is-bigint": "^1.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/word-wrap": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
- "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
- },
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
- "node_modules/yocto-queue": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
- "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- }
- }
-}
diff --git a/opendc-web/opendc-web-ui/package.json b/opendc-web/opendc-web-ui/package.json
deleted file mode 100644
index 18840db6..00000000
--- a/opendc-web/opendc-web-ui/package.json
+++ /dev/null
@@ -1,76 +0,0 @@
-{
- "name": "opendc-frontend",
- "version": "3.0.0",
- "description": "The user-facing component of the OpenDC stack, allowing users to build and interact with their own (virtual) datacenters.",
- "keywords": [
- "opendc",
- "simulation",
- "datacenter",
- "frontend"
- ],
- "homepage": "http://opendc.org",
- "bugs": {
- "url": "https://github.com/atlarge-research/opendc/issues",
- "email": "opendc@atlarge-research.com"
- },
- "author": "OpenDC Maintainers <opendc@atlarge-research.com>",
- "license": "MIT",
- "private": true,
- "dependencies": {
- "@auth0/auth0-react": "^1.12.1",
- "@patternfly/react-charts": "^6.94.18",
- "@patternfly/react-core": "^4.276.6",
- "@patternfly/react-icons": "^4.93.6",
- "@patternfly/react-table": "^4.112.39",
- "@sentry/react": "^7.45.0",
- "@sentry/tracing": "^7.45.0",
- "clsx": "^1.2.1",
- "immer": "^9.0.21",
- "konva": "^8.4.3",
- "mathjs": "^11.7.0",
- "next": "^13.5.4",
- "next-global-css": "^1.3.1",
- "normalizr": "^3.6.2",
- "prettier": "^2.8.7",
- "prop-types": "^15.8.1",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
- "react-hotkeys-hook": "^4.3.8",
- "react-konva": "^18.2.5",
- "react-query": "^3.39.3",
- "react-redux": "^8.0.5",
- "redux": "^4.2.1",
- "redux-logger": "^3.0.6",
- "redux-saga": "^1.2.3",
- "redux-thunk": "^2.4.2",
- "svgsaver": "^0.9.0",
- "use-resize-observer": "^9.1.0",
- "uuid": "^9.0.0",
- "victory-errorbar": "^36.6.8"
- },
- "devDependencies": {
- "eslint": "^8.36.0",
- "eslint-config-next": "^13.2.4"
- },
- "scripts": {
- "format": "prettier --write src",
- "precommit": "lint-staged",
- "dev": "next dev",
- "lint": "next lint",
- "build": "next build",
- "start": "next start",
- "export": "next export -o build/export"
- },
- "browserslist": {
- "production": [
- ">0.2%",
- "not dead",
- "not op_mini all"
- ],
- "development": [
- "last 1 chrome version",
- "last 1 firefox version",
- "last 1 safari version"
- ]
- }
-}
diff --git a/opendc-web/opendc-web-ui/public/favicon.ico b/opendc-web/opendc-web-ui/public/favicon.ico
deleted file mode 100644
index c2f40a0d..00000000
--- a/opendc-web/opendc-web-ui/public/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/humans.txt b/opendc-web/opendc-web-ui/public/humans.txt
deleted file mode 100644
index dadcd530..00000000
--- a/opendc-web/opendc-web-ui/public/humans.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-/* TEAM */
-Benevolent Dictator for Life: Alexandru Iosup.
-Site: http://www.ds.ewi.tudelft.nl/~iosup/
-Twitter: aiosup.
-Location: Delft, Netherlands.
-
-Full-Stack Engineer: Georgios Andreadis.
-Site: https://github.com/gandreadis
-Location: Delft, Netherlands.
-
-Simulation Engineer: Fabian Mastenbroek.
-Site: https://github.com/fabianishere
-Location: Delft, Netherlands.
-
-Simulation Engineer: Jacob Burley.
-Site: https://github.com/jc0b
-Location: Amsterdam, Netherlands.
-
-Backend Engineer: Leon Overweel.
-Site: http://leonoverweel.com/
-Twitter: layon_overwhale.
-Location: Delft, Netherlands.
-
-Simulation Engineer: Matthijs Bijman.
-Site: https://github.com/MDBijman
-Location: Delft, Netherlands.
-
-/* THANKS */
-Executive Producer: Vincent van Beek.
-Executive Producer: Tim Hegeman.
-
-/* SITE */
-Standards: HTML5, Sass, ES6
-Components: React.js, Redux, create-react-app, react-konva
-Software: WebStorm, Vim, Visual Studio
diff --git a/opendc-web/opendc-web-ui/public/img/avatar.svg b/opendc-web/opendc-web-ui/public/img/avatar.svg
deleted file mode 100644
index 73726f9b..00000000
--- a/opendc-web/opendc-web-ui/public/img/avatar.svg
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 24.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- viewBox="0 0 36 36" style="enable-background:new 0 0 36 36;" xml:space="preserve">
-<style type="text/css">
- .st0{fill-rule:evenodd;clip-rule:evenodd;fill:#F0F0F0;}
- .st1{fill-rule:evenodd;clip-rule:evenodd;fill:#D2D2D2;}
- .st2{fill:#B8BBBE;}
- .st3{fill:#D2D2D2;}
-</style>
-<rect class="st0" width="36" height="36"/>
-<path class="st1" d="M17.7,20.1c-3.5,0-6.4-2.9-6.4-6.4s2.9-6.4,6.4-6.4s6.4,2.9,6.4,6.4S21.3,20.1,17.7,20.1z"/>
-<path class="st2" d="M13.3,36l0-6.7c-2,0.4-2.9,1.4-3.1,3.5L10.1,36H13.3z"/>
-<path class="st3" d="M10.1,36l0.1-3.2c0.2-2.1,1.1-3.1,3.1-3.5l0,6.7h9.4l0-6.7c2,0.4,2.9,1.4,3.1,3.5l0.1,3.2h4.7
- c-0.4-3.9-1.3-9-2.9-11c-1.1-1.4-2.3-2.2-3.5-2.6s-1.8-0.6-6.3-0.6s-6.1,0.7-6.1,0.7c-1.2,0.4-2.4,1.2-3.4,2.6
- C6.7,27,5.8,32.2,5.4,36H10.1z"/>
-<path class="st2" d="M25.9,36l-0.1-3.2c-0.2-2.1-1.1-3.1-3.1-3.5l0,6.7H25.9z"/>
-</svg>
diff --git a/opendc-web/opendc-web-ui/public/img/datacenter-drawing.png b/opendc-web/opendc-web-ui/public/img/datacenter-drawing.png
deleted file mode 100644
index ec2b7398..00000000
--- a/opendc-web/opendc-web-ui/public/img/datacenter-drawing.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/logo.png b/opendc-web/opendc-web-ui/public/img/logo.png
deleted file mode 100644
index d743038b..00000000
--- a/opendc-web/opendc-web-ui/public/img/logo.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/logo.svg b/opendc-web/opendc-web-ui/public/img/logo.svg
deleted file mode 100644
index 5283a034..00000000
--- a/opendc-web/opendc-web-ui/public/img/logo.svg
+++ /dev/null
@@ -1,191 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="4.3656249mm"
- height="5.4239674mm"
- viewBox="0 0 4.3656249 5.4239674"
- version="1.1"
- id="svg4738"
- inkscape:version="0.92.1 r15371"
- sodipodi:docname="opendc.svg">
- <defs
- id="defs4732" />
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="22.4"
- inkscape:cx="-5.0874286"
- inkscape:cy="6.401307"
- inkscape:document-units="mm"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:window-width="1920"
- inkscape:window-height="1027"
- inkscape:window-x="-8"
- inkscape:window-y="-8"
- inkscape:window-maximized="1" />
- <metadata
- id="metadata4735">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title></dc:title>
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-16.538532,-146.52225)">
- <g
- transform="matrix(0.26458333,0,0,0.26458333,-15.13354,-112.7517)"
- id="g4333"
- inkscape:export-filename="h:\Desktop\logo.png"
- inkscape:export-xdpi="561.54816"
- inkscape:export-ydpi="561.54816">
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\stackv2.png"
- style="fill:#48a1cd;fill-opacity:1;stroke:none"
- d="m 119.95547,988.18306 8,4 v -4 l -8,-4 z"
- id="path4052-1-2-8"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\stackv2.png"
- style="fill:#82d0e7;fill-opacity:1;stroke:none"
- d="m 127.95547,988.18306 v 4 l 8.00001,-4 v -4 z"
- id="path4054-4-9-2"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\stackv2.png"
- style="fill:#82d0e7;fill-opacity:1;stroke:none"
- d="m 119.95547,984.18306 8,-4 8.00001,4 -8.00001,4 z"
- id="path4056-2-1-5"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- inkscape:connector-curvature="0"
- id="path4048-1-9"
- d="m 119.95547,992.18306 8,4 v -4 l -8,-4 z"
- style="fill:#d1af2e;fill-opacity:1;stroke:none" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- inkscape:connector-curvature="0"
- id="path4050-7-2"
- d="m 127.95546,992.18306 v 4 l 8.00001,-4 v -4 z"
- style="fill:#edd667;fill-opacity:1;stroke:none" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- style="fill:#df6f20;fill-opacity:1;stroke:none"
- d="m 119.95547,996.18306 8,4.00004 v -4.00004 l -8,-4 z"
- id="path3883-9-9-8"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- style="fill:#ed9c67;fill-opacity:1;stroke:none"
- d="m 127.95547,996.18306 v 4.00004 l 8,-4.00004 v -4 z"
- id="path3885-8-9-1"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
- d="m 119.95547,984.18306 8,-4 8,4 -8,4 z"
- id="path3893-6-0-8"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- d="m 119.95547,984.18306 v 4 l 8,4 8,-4 v -4"
- id="path3895-2-6-1"
- inkscape:connector-curvature="0" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
- d="m 127.95547,988.18306 v 12.00004"
- id="path3897-3-2-1"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="cc" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- inkscape:connector-curvature="0"
- id="path3899-8-1-7"
- d="m 119.95547,988.18306 v 4 l 8,4 8,-4 v -4"
- style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
- <path
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\comparison.png"
- style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
- d="m 119.95547,992.18306 v 4 l 8,4.00004 8,-4.00004 v -4"
- id="path3901-5-6-1"
- inkscape:connector-curvature="0" />
- <circle
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\stackv2.png"
- transform="matrix(1.0403949,-0.44307824,0.3060712,0.9369482,-235.62413,33.696703)"
- id="path3906-6-2-4-1-2"
- style="fill:#000000;fill-opacity:1;stroke:none"
- cx="43.5"
- cy="1044.8622"
- r="0.5" />
- <circle
- inkscape:export-ydpi="1307.2168"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-filename="h:\Desktop\stackv2.png"
- transform="matrix(1.0403949,-0.44307824,0.3060712,0.9369482,-235.62413,37.696663)"
- id="path3910-3-0-1-9-1"
- style="fill:#000000;fill-opacity:1;stroke:none"
- cx="43.5"
- cy="1044.8622"
- r="0.5" />
- <circle
- style="fill:#000000;fill-opacity:1;stroke:none"
- id="path4108-7-3-6"
- transform="matrix(1.0403949,-0.44307824,0.3060712,0.9369482,-235.62413,29.696659)"
- inkscape:export-filename="h:\Desktop\stackv2.png"
- inkscape:export-xdpi="1307.2168"
- inkscape:export-ydpi="1307.2168"
- cx="43.5"
- cy="1044.8622"
- r="0.5" />
- </g>
- </g>
-</svg>
diff --git a/opendc-web/opendc-web-ui/public/img/opendc-architecture.png b/opendc-web/opendc-web-ui/public/img/opendc-architecture.png
deleted file mode 100644
index e0bf8e9b..00000000
--- a/opendc-web/opendc-web-ui/public/img/opendc-architecture.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/opendc-timeline-v2.png b/opendc-web/opendc-web-ui/public/img/opendc-timeline-v2.png
deleted file mode 100644
index 0b2821c4..00000000
--- a/opendc-web/opendc-web-ui/public/img/opendc-timeline-v2.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/aiosup.png b/opendc-web/opendc-web-ui/public/img/portraits/aiosup.png
deleted file mode 100644
index d2019b4d..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/aiosup.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/evaneyk.png b/opendc-web/opendc-web-ui/public/img/portraits/evaneyk.png
deleted file mode 100644
index 011c1627..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/evaneyk.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/fmastenbroek.png b/opendc-web/opendc-web-ui/public/img/portraits/fmastenbroek.png
deleted file mode 100644
index 218b1a6f..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/fmastenbroek.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/gandreadis.png b/opendc-web/opendc-web-ui/public/img/portraits/gandreadis.png
deleted file mode 100644
index 96a3abda..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/gandreadis.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/hhe.png b/opendc-web/opendc-web-ui/public/img/portraits/hhe.png
deleted file mode 100644
index 4891c7f5..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/hhe.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/jbosch.png b/opendc-web/opendc-web-ui/public/img/portraits/jbosch.png
deleted file mode 100644
index c76e1fab..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/jbosch.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/jburley.png b/opendc-web/opendc-web-ui/public/img/portraits/jburley.png
deleted file mode 100644
index d2691659..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/jburley.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/lfdversluis.png b/opendc-web/opendc-web-ui/public/img/portraits/lfdversluis.png
deleted file mode 100644
index 6fbc8472..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/lfdversluis.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/loverweel.png b/opendc-web/opendc-web-ui/public/img/portraits/loverweel.png
deleted file mode 100644
index 85865977..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/loverweel.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/sjounaid.png b/opendc-web/opendc-web-ui/public/img/portraits/sjounaid.png
deleted file mode 100644
index 41878161..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/sjounaid.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/vvanbeek.png b/opendc-web/opendc-web-ui/public/img/portraits/vvanbeek.png
deleted file mode 100644
index 4c8b3311..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/vvanbeek.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/portraits/wlai.png b/opendc-web/opendc-web-ui/public/img/portraits/wlai.png
deleted file mode 100644
index c758846d..00000000
--- a/opendc-web/opendc-web-ui/public/img/portraits/wlai.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/screenshot-construction.png b/opendc-web/opendc-web-ui/public/img/screenshot-construction.png
deleted file mode 100644
index ea20a7c4..00000000
--- a/opendc-web/opendc-web-ui/public/img/screenshot-construction.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/screenshot-simulation.png b/opendc-web/opendc-web-ui/public/img/screenshot-simulation.png
deleted file mode 100644
index 1bd989c7..00000000
--- a/opendc-web/opendc-web-ui/public/img/screenshot-simulation.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/stakeholders/Developer.png b/opendc-web/opendc-web-ui/public/img/stakeholders/Developer.png
deleted file mode 100644
index d2638e6c..00000000
--- a/opendc-web/opendc-web-ui/public/img/stakeholders/Developer.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/stakeholders/Manager.png b/opendc-web/opendc-web-ui/public/img/stakeholders/Manager.png
deleted file mode 100644
index 92db7459..00000000
--- a/opendc-web/opendc-web-ui/public/img/stakeholders/Manager.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/stakeholders/Researcher.png b/opendc-web/opendc-web-ui/public/img/stakeholders/Researcher.png
deleted file mode 100644
index d87edd39..00000000
--- a/opendc-web/opendc-web-ui/public/img/stakeholders/Researcher.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/stakeholders/Sales.png b/opendc-web/opendc-web-ui/public/img/stakeholders/Sales.png
deleted file mode 100644
index 5b7c3a72..00000000
--- a/opendc-web/opendc-web-ui/public/img/stakeholders/Sales.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/stakeholders/Student.png b/opendc-web/opendc-web-ui/public/img/stakeholders/Student.png
deleted file mode 100644
index a4900303..00000000
--- a/opendc-web/opendc-web-ui/public/img/stakeholders/Student.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/topology/cpu-icon.png b/opendc-web/opendc-web-ui/public/img/topology/cpu-icon.png
deleted file mode 100644
index 07cfbd31..00000000
--- a/opendc-web/opendc-web-ui/public/img/topology/cpu-icon.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/topology/gpu-icon.png b/opendc-web/opendc-web-ui/public/img/topology/gpu-icon.png
deleted file mode 100644
index 55d4fb05..00000000
--- a/opendc-web/opendc-web-ui/public/img/topology/gpu-icon.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/topology/memory-icon.png b/opendc-web/opendc-web-ui/public/img/topology/memory-icon.png
deleted file mode 100644
index 36e8a44e..00000000
--- a/opendc-web/opendc-web-ui/public/img/topology/memory-icon.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/topology/rack-energy-icon.png b/opendc-web/opendc-web-ui/public/img/topology/rack-energy-icon.png
deleted file mode 100644
index 1088c61b..00000000
--- a/opendc-web/opendc-web-ui/public/img/topology/rack-energy-icon.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/topology/rack-space-icon.png b/opendc-web/opendc-web-ui/public/img/topology/rack-space-icon.png
deleted file mode 100644
index 387d7ea6..00000000
--- a/opendc-web/opendc-web-ui/public/img/topology/rack-space-icon.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/topology/storage-icon.png b/opendc-web/opendc-web-ui/public/img/topology/storage-icon.png
deleted file mode 100644
index 7a39cb6f..00000000
--- a/opendc-web/opendc-web-ui/public/img/topology/storage-icon.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/img/tudelft-icon.png b/opendc-web/opendc-web-ui/public/img/tudelft-icon.png
deleted file mode 100644
index a7a2d56a..00000000
--- a/opendc-web/opendc-web-ui/public/img/tudelft-icon.png
+++ /dev/null
Binary files differ
diff --git a/opendc-web/opendc-web-ui/public/manifest.json b/opendc-web/opendc-web-ui/public/manifest.json
deleted file mode 100644
index adb82218..00000000
--- a/opendc-web/opendc-web-ui/public/manifest.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "short_name": "OpenDC",
- "name": "OpenDC",
- "icons": [
- {
- "src": "favicon.ico",
- "sizes": "16x16",
- "type": "image/png"
- }
- ],
- "start_url": "./index.html",
- "display": "standalone",
- "theme_color": "#00A6D6",
- "background_color": "#eeeeee"
-}
diff --git a/opendc-web/opendc-web-ui/public/robots.txt b/opendc-web/opendc-web-ui/public/robots.txt
deleted file mode 100644
index 1c6094ce..00000000
--- a/opendc-web/opendc-web-ui/public/robots.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-User-agent: *
-Disallow: /projects/
-Disallow: /profile/
diff --git a/opendc-web/opendc-web-ui/scripts/envsubst.sh b/opendc-web/opendc-web-ui/scripts/envsubst.sh
deleted file mode 100755
index afc976ed..00000000
--- a/opendc-web/opendc-web-ui/scripts/envsubst.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-
-set -e
-
-auto_envsubst() {
- input_path="build/next.template"
- output_path="build/next"
-
- cp -r "$input_path" "$output_path"
- find "$output_path" -type f -name '*.js' -exec perl -pi -e 's/%%(NEXT_PUBLIC_[_A-Z0-9]+)%%/$ENV{$1}/g' {} \;
-}
-
-auto_envsubst
-exit 0
diff --git a/opendc-web/opendc-web-ui/src/api/index.js b/opendc-web/opendc-web-ui/src/api/index.js
deleted file mode 100644
index 3411b96e..00000000
--- a/opendc-web/opendc-web-ui/src/api/index.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { apiUrl } from '../config'
-
-/**
- * Send the specified request to the OpenDC API.
- *
- * @param auth The authentication context.
- * @param path Relative path for the API.
- * @param method The method to use for the request.
- * @param body The body of the request.
- */
-export async function request(auth, path, method = 'GET', body) {
- const headers = {
- 'Content-Type': 'application/json',
- }
-
- const { getAccessTokenSilently } = auth
- if (getAccessTokenSilently) {
- const token = await getAccessTokenSilently()
- headers['Authorization'] = `Bearer ${token}`
- }
-
- const response = await fetch(`${apiUrl}/${path}`, {
- method: method,
- headers: headers,
- body: body && JSON.stringify(body),
- })
- const json = await response.json()
-
- if (!response.ok) {
- throw json.message
- }
-
- return json
-}
diff --git a/opendc-web/opendc-web-ui/src/api/portfolios.js b/opendc-web/opendc-web-ui/src/api/portfolios.js
deleted file mode 100644
index d818876f..00000000
--- a/opendc-web/opendc-web-ui/src/api/portfolios.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { request } from './index'
-
-export function fetchPortfolio(auth, projectId, number) {
- return request(auth, `projects/${projectId}/portfolios/${number}`)
-}
-
-export function fetchPortfolios(auth, projectId) {
- return request(auth, `projects/${projectId}/portfolios`)
-}
-
-export function addPortfolio(auth, projectId, portfolio) {
- return request(auth, `projects/${projectId}/portfolios`, 'POST', portfolio)
-}
-
-export function deletePortfolio(auth, projectId, number) {
- return request(auth, `projects/${projectId}/portfolios/${number}`, 'DELETE')
-}
diff --git a/opendc-web/opendc-web-ui/src/api/projects.js b/opendc-web/opendc-web-ui/src/api/projects.js
deleted file mode 100644
index e7e095da..00000000
--- a/opendc-web/opendc-web-ui/src/api/projects.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { request } from './index'
-
-export function fetchProjects(auth) {
- return request(auth, `projects/`)
-}
-
-export function fetchProject(auth, projectId) {
- return request(auth, `projects/${projectId}`)
-}
-
-export function addProject(auth, project) {
- return request(auth, 'projects/', 'POST', project)
-}
-
-export function deleteProject(auth, projectId) {
- return request(auth, `projects/${projectId}`, 'DELETE')
-}
diff --git a/opendc-web/opendc-web-ui/src/api/scenarios.js b/opendc-web/opendc-web-ui/src/api/scenarios.js
deleted file mode 100644
index 7eeb8f28..00000000
--- a/opendc-web/opendc-web-ui/src/api/scenarios.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { request } from './index'
-
-export function fetchScenario(auth, projectId, scenarioId) {
- return request(auth, `projects/${projectId}/scenarios/${scenarioId}`)
-}
-
-export function fetchScenariosOfPortfolio(auth, projectId, portfolioId) {
- return request(auth, `projects/${projectId}/portfolios/${portfolioId}/scenarios`)
-}
-
-export function addScenario(auth, projectId, portfolioId, scenario) {
- return request(auth, `projects/${projectId}/portfolios/${portfolioId}/scenarios`, 'POST', scenario)
-}
-
-export function deleteScenario(auth, projectId, scenarioId) {
- return request(auth, `projects/${projectId}/scenarios/${scenarioId}`, 'DELETE')
-}
diff --git a/opendc-web/opendc-web-ui/src/api/schedulers.js b/opendc-web/opendc-web-ui/src/api/schedulers.js
deleted file mode 100644
index 0b8b8153..00000000
--- a/opendc-web/opendc-web-ui/src/api/schedulers.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { request } from './index'
-
-export function fetchSchedulers(auth) {
- return request(auth, 'schedulers/')
-}
diff --git a/opendc-web/opendc-web-ui/src/api/topologies.js b/opendc-web/opendc-web-ui/src/api/topologies.js
deleted file mode 100644
index 0509c6d0..00000000
--- a/opendc-web/opendc-web-ui/src/api/topologies.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { request } from './index'
-
-export function fetchTopology(auth, projectId, number) {
- return request(auth, `projects/${projectId}/topologies/${number}`)
-}
-
-export function fetchTopologies(auth, projectId) {
- return request(auth, `projects/${projectId}/topologies`)
-}
-
-export function addTopology(auth, projectId, topology) {
- return request(auth, `projects/${projectId}/topologies`, 'POST', topology)
-}
-
-export function updateTopology(auth, topology) {
- const { project, number, rooms } = topology
- return request(auth, `projects/${project.id}/topologies/${number}`, 'PUT', { rooms })
-}
-
-export function deleteTopology(auth, projectId, number) {
- return request(auth, `projects/${projectId}/topologies/${number}`, 'DELETE')
-}
diff --git a/opendc-web/opendc-web-ui/src/api/traces.js b/opendc-web/opendc-web-ui/src/api/traces.js
deleted file mode 100644
index fd637ac3..00000000
--- a/opendc-web/opendc-web-ui/src/api/traces.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { request } from './index'
-
-export function fetchTraces(auth) {
- return request(auth, 'traces/')
-}
diff --git a/opendc-web/opendc-web-ui/src/api/users.js b/opendc-web/opendc-web-ui/src/api/users.js
deleted file mode 100644
index 12a9be05..00000000
--- a/opendc-web/opendc-web-ui/src/api/users.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { request } from './index'
-
-/**
- * Fetch information about the user from the web server.
- *
- * @param auth The authentication object.
- */
-export function fetchUser(auth) {
- return request(auth, `users/me`)
-}
diff --git a/opendc-web/opendc-web-ui/src/auth.js b/opendc-web/opendc-web-ui/src/auth.js
deleted file mode 100644
index 8c88f526..00000000
--- a/opendc-web/opendc-web-ui/src/auth.js
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { Auth0Provider, useAuth0 } from '@auth0/auth0-react'
-import { useEffect } from 'react'
-import { auth } from './config'
-
-/**
- * Helper function to provide the authentication context in case Auth0 is not
- * configured and the user is anonymous.
- */
-function useAnonymousAuth() {
- return {
- isAnonymous: true,
- isAuthenticated: false,
- isLoading: false,
- logout: () => {},
- loginWithRedirect: () => {},
- }
-}
-
-/**
- * Determine whether the auth domain is anonymous.
- */
-function isAnonymousDomain(config) {
- return !config.domain || config.domain === '%%NEXT_PUBLIC_AUTH0_DOMAIN%%'
-}
-
-/**
- * Force the user to be authenticated or redirect to the homepage.
- */
-function useRequireAuth0() {
- const auth = useAuth0()
- const { loginWithRedirect, isLoading, isAuthenticated } = auth
-
- useEffect(() => {
- if (!isLoading && !isAuthenticated) {
- loginWithRedirect()
- }
- }, [loginWithRedirect, isLoading, isAuthenticated])
-}
-
-/**
- * Obtain the authentication context.
- */
-export const useAuth = isAnonymousDomain(auth) ? useAnonymousAuth : useAuth0
-
-/**
- * Force the user to be authenticated or redirect to the homepage.
- */
-export const useRequireAuth = isAnonymousDomain(auth) ? () => {} : useRequireAuth0
-
-/**
- * AuthProvider which provides an authentication context.
- */
-export function AuthProvider({ children }) {
- const authConfig = auth
-
- if (!isAnonymousDomain(authConfig)) {
- return (
- <Auth0Provider
- domain={authConfig.domain}
- clientId={authConfig.clientId}
- redirectUri={authConfig.redirectUri}
- audience={authConfig.audience}
- >
- {children}
- </Auth0Provider>
- )
- }
-
- return children
-}
-
-AuthProvider.propTypes = {
- children: PropTypes.node,
-}
diff --git a/opendc-web/opendc-web-ui/src/components/AppHeader.js b/opendc-web/opendc-web-ui/src/components/AppHeader.js
deleted file mode 100644
index 514dce2a..00000000
--- a/opendc-web/opendc-web-ui/src/components/AppHeader.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import Image from 'next/image'
-import PropTypes from 'prop-types'
-import React from 'react'
-import {
- Masthead,
- MastheadMain,
- MastheadBrand,
- MastheadContent,
- Toolbar,
- ToolbarContent,
- ToolbarItem,
-} from '@patternfly/react-core'
-import Link from 'next/link'
-import AppHeaderTools from './AppHeaderTools'
-import AppHeaderUser from './AppHeaderUser'
-import ProjectSelector from './context/ProjectSelector'
-
-import styles from './AppHeader.module.css'
-
-export default function AppHeader({ nav }) {
- return (
- <Masthead id="app-header" className={styles.header}>
- <MastheadMain>
- <MastheadBrand className={styles.logo} component={(props) => <Link href="/projects" {...props} />}>
- <Image src="/img/logo.svg" alt="OpenDC logo" width={25} height={25} />
- <span>OpenDC</span>
- </MastheadBrand>
- </MastheadMain>
- <MastheadContent>
- <Toolbar id="toolbar" isFullHeight isStatic>
- <ToolbarContent>
- <ToolbarItem>
- <ProjectSelector />
- </ToolbarItem>
- {nav && <ToolbarItem>{nav}</ToolbarItem>}
- <AppHeaderTools />
- <AppHeaderUser />
- </ToolbarContent>
- </Toolbar>
- </MastheadContent>
- </Masthead>
- )
-}
-
-AppHeader.propTypes = {
- nav: PropTypes.node,
-}
diff --git a/opendc-web/opendc-web-ui/src/components/AppHeader.module.css b/opendc-web/opendc-web-ui/src/components/AppHeader.module.css
deleted file mode 100644
index 9d5dbed1..00000000
--- a/opendc-web/opendc-web-ui/src/components/AppHeader.module.css
+++ /dev/null
@@ -1,42 +0,0 @@
-/*!
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-.header.header {
- /* Increase precedence */
- --pf-c-masthead--m-display-inline__content--MinHeight: 3rem;
- --pf-c-masthead--m-display-inline__main--MinHeight: 3rem;
-
- --pf-c-masthead--c-context-selector--Width: 200px;
-}
-
-.logo > span {
- margin-left: 8px;
- color: #fff;
- align-self: center;
- font-weight: 600;
- font-size: 0.9rem;
-}
-
-.logo:hover,
-.logo:focus > span {
- --pf-global--link--TextDecoration: none;
-}
diff --git a/opendc-web/opendc-web-ui/src/components/AppHeaderTools.js b/opendc-web/opendc-web-ui/src/components/AppHeaderTools.js
deleted file mode 100644
index 499bceef..00000000
--- a/opendc-web/opendc-web-ui/src/components/AppHeaderTools.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import {
- Button,
- ButtonVariant,
- Dropdown,
- DropdownItem,
- KebabToggle,
- ToolbarGroup,
- ToolbarItem,
-} from '@patternfly/react-core'
-import { useReducer } from 'react'
-import { GithubIcon, HelpIcon } from '@patternfly/react-icons'
-
-function AppHeaderTools() {
- const [isKebabDropdownOpen, toggleKebabDropdown] = useReducer((t) => !t, false)
- const kebabDropdownItems = [
- <DropdownItem
- key={0}
- component={
- <a href="https://opendc.org" target="_blank" rel="noreferrer">
- <HelpIcon /> Help
- </a>
- }
- />,
- ]
-
- return (
- <ToolbarGroup
- variant="icon-button-group"
- alignment={{ default: 'alignRight' }}
- spacer={{ default: 'spacerNone', md: 'spacerMd' }}
- >
- <ToolbarGroup variant="icon-button-group" visibility={{ default: 'hidden', lg: 'visible' }}>
- <ToolbarItem>
- <Button
- component="a"
- href="https://github.com/atlarge-research/opendc"
- target="_blank"
- aria-label="Source code"
- variant={ButtonVariant.plain}
- >
- <GithubIcon />
- </Button>
- </ToolbarItem>
- <ToolbarItem>
- <Button
- component="a"
- href="https://opendc.org/"
- target="_blank"
- aria-label="Help actions"
- variant={ButtonVariant.plain}
- >
- <HelpIcon />
- </Button>
- </ToolbarItem>
- </ToolbarGroup>
- <ToolbarItem visibility={{ lg: 'hidden' }}>
- <Dropdown
- isPlain
- position="right"
- toggle={<KebabToggle onToggle={toggleKebabDropdown} />}
- isOpen={isKebabDropdownOpen}
- dropdownItems={kebabDropdownItems}
- />
- </ToolbarItem>
- </ToolbarGroup>
- )
-}
-
-AppHeaderTools.propTypes = {}
-
-export default AppHeaderTools
diff --git a/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js b/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js
deleted file mode 100644
index 3a73d9ba..00000000
--- a/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import {
- Dropdown,
- DropdownToggle,
- Skeleton,
- ToolbarItem,
- DropdownItem,
- DropdownGroup,
- Avatar,
- Progress,
- ProgressSize,
- DropdownSeparator,
-} from '@patternfly/react-core'
-import { useReducer } from 'react'
-import { useAuth } from '../auth'
-import useUser from '../data/user'
-
-export default function AppHeaderUser() {
- const { logout, user, isAuthenticated, isLoading } = useAuth()
- const username = isAuthenticated || isLoading ? user?.name : 'Anonymous'
- const avatar = isAuthenticated || isLoading ? user?.picture : '/img/avatar.svg'
-
- const { data } = useUser()
- const simulationBudget = data?.accounting?.simulationTimeBudget ?? 3600
- const simulationTime = data?.accounting?.simulationTime | 0
-
- const [isDropdownOpen, toggleDropdown] = useReducer((t) => !t, false)
- const userDropdownItems = [
- <DropdownGroup key="budget" label="Monthly Simulation Budget">
- <DropdownItem isDisabled>
- <Progress
- min={0}
- max={simulationBudget}
- value={simulationTime}
- title={`${Math.ceil(simulationTime / 60)} of ${Math.ceil(simulationBudget / 60)} minutes`}
- size={ProgressSize.sm}
- />
- </DropdownItem>
- </DropdownGroup>,
- <DropdownSeparator key="separator" />,
- <DropdownItem
- key="group 2 logout"
- isDisabled={!isAuthenticated}
- onClick={() => logout({ returnTo: window.location.origin })}
- >
- Logout
- </DropdownItem>,
- ]
-
- const avatarComponent = avatar ? (
- <Avatar src={avatar} alt="Avatar image" size="sm" />
- ) : (
- <Skeleton className="pf-c-avatar" shape="circle" width="24px" screenreaderText="Loading avatar" />
- )
-
- return (
- <ToolbarItem visibility={{ default: 'hidden', md: 'visible' }}>
- <Dropdown
- isFullHeight
- position="right"
- isOpen={isDropdownOpen}
- toggle={
- <DropdownToggle onToggle={toggleDropdown} icon={avatarComponent}>
- {username ?? (
- <Skeleton
- fontSize="xs"
- width="150px"
- className="pf-u-display-inline-flex"
- screenreaderText="Loading username"
- />
- )}
- </DropdownToggle>
- }
- dropdownItems={userDropdownItems}
- />
- </ToolbarItem>
- )
-}
diff --git a/opendc-web/opendc-web-ui/src/components/AppPage.js b/opendc-web/opendc-web-ui/src/components/AppPage.js
deleted file mode 100644
index 2893146e..00000000
--- a/opendc-web/opendc-web-ui/src/components/AppPage.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import AppHeader from './AppHeader'
-import React from 'react'
-import { Page, PageGroup, PageBreadcrumb } from '@patternfly/react-core'
-
-export function AppPage({ children, breadcrumb, contextSelectors }) {
- return (
- <Page header={<AppHeader />}>
- <PageGroup>
- {contextSelectors}
- {breadcrumb && <PageBreadcrumb>{breadcrumb}</PageBreadcrumb>}
- </PageGroup>
- {children}
- </Page>
- )
-}
-
-AppPage.propTypes = {
- breadcrumb: PropTypes.node,
- contextSelectors: PropTypes.node,
- children: PropTypes.node,
-}
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js b/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js
deleted file mode 100644
index f3c25b79..00000000
--- a/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { contextSelectionSection } from './ContextSelectionSection.module.css'
-
-function ContextSelectionSection({ children }) {
- return <section className={contextSelectionSection}>{children}</section>
-}
-
-ContextSelectionSection.propTypes = {
- children: PropTypes.node,
-}
-
-export default ContextSelectionSection
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.css b/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.css
deleted file mode 100644
index 0e902af0..00000000
--- a/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.css
+++ /dev/null
@@ -1,28 +0,0 @@
-/*!
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-.contextSelectionSection {
- padding-left: var(--pf-c-page__main-breadcrumb--PaddingLeft);
- flex-shrink: 0;
- border-bottom: var(--pf-global--BorderWidth--sm) solid var(--pf-global--BorderColor--100);
- background-color: var(--pf-c-page__main-breadcrumb--BackgroundColor);
-}
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js
deleted file mode 100644
index d2601008..00000000
--- a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { ContextSelector as PFContextSelector, ContextSelectorItem } from '@patternfly/react-core'
-import { useMemo, useState } from 'react'
-
-import styles from './ContextSelector.module.css'
-
-function ContextSelector({ id, type = 'page', toggleText, items, onSelect, onToggle, isOpen, isFullHeight }) {
- const [searchValue, setSearchValue] = useState('')
- const filteredItems = useMemo(
- () => items.filter(({ name }) => name.toLowerCase().indexOf(searchValue.toLowerCase()) !== -1) || items,
- [items, searchValue]
- )
-
- return (
- <PFContextSelector
- id={id}
- className={type === 'page' && styles.pageSelector}
- toggleText={toggleText}
- onSearchInputChange={(value) => setSearchValue(value)}
- searchInputValue={searchValue}
- onToggle={(_, isOpen) => onToggle(isOpen)}
- onSelect={(event) => {
- const targetId = +event.target.value
- const target = items.find((item) => item.id === targetId)
-
- onSelect(target)
- onToggle(!isOpen)
- }}
- isOpen={isOpen}
- isFullHeight={isFullHeight}
- >
- {filteredItems.map((item) => (
- <ContextSelectorItem key={item.id} value={item.id}>
- {item.name}
- </ContextSelectorItem>
- ))}
- </PFContextSelector>
- )
-}
-
-const Item = PropTypes.shape({
- id: PropTypes.any.isRequired,
- name: PropTypes.string.isRequired,
-})
-
-ContextSelector.propTypes = {
- id: PropTypes.string,
- type: PropTypes.oneOf(['app', 'page']),
- items: PropTypes.arrayOf(Item).isRequired,
- toggleText: PropTypes.string,
- onSelect: PropTypes.func.isRequired,
- onToggle: PropTypes.func.isRequired,
- isOpen: PropTypes.bool,
- isFullHeight: PropTypes.bool,
-}
-
-export default ContextSelector
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.css b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.css
deleted file mode 100644
index 7662d00c..00000000
--- a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.css
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-.pageSelector.pageSelector {
- /* Ensure this selector has precedence over the default one */
- margin-right: 20px;
-
- --pf-c-context-selector__menu--ZIndex: var(--pf-global--ZIndex--lg);
- --pf-c-context-selector__toggle--PaddingTop: var(--pf-global--spacer--sm);
- --pf-c-context-selector__toggle--PaddingRight: 0;
- --pf-c-context-selector__toggle--PaddingBottom: var(--pf-global--spacer--sm);
- --pf-c-context-selector__toggle--PaddingLeft: 0;
- --pf-c-context-selector__toggle--BorderWidth: 0;
- --pf-c-context-selector__toggle-text--FontSize: var(--pf-global--FontSize--sm);
-}
-
-.pageSelector.pageSelector :global(.pf-c-context-selector__toggle):active,
-.pageSelector.pageSelector :global(.pf-c-context-selector__toggle):focus-within,
-.pageSelector.pageSelector :global(.pf-c-context-selector__toggle):global(.pf-m-active) {
- --pf-c-context-selector__toggle--after--BorderBottomWidth: 0;
-}
-
-.pageSelector.pageSelector:global(.pf-m-expanded) > :global(.pf-c-context-selector__toggle) {
- --pf-c-context-selector__toggle--after--BorderBottomWidth: 0;
-}
diff --git a/opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js b/opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js
deleted file mode 100644
index e401e6fc..00000000
--- a/opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useRouter } from 'next/router'
-import { useState } from 'react'
-import { usePortfolios } from '../../data/project'
-import { Portfolio } from '../../shapes'
-import ContextSelector from './ContextSelector'
-
-function PortfolioSelector({ activePortfolio }) {
- const router = useRouter()
-
- const [isOpen, setOpen] = useState(false)
- const { data: portfolios = [] } = usePortfolios(activePortfolio?.project?.id, { enabled: isOpen })
-
- return (
- <ContextSelector
- id="portfolio"
- toggleText={activePortfolio ? `Portfolio: ${activePortfolio.name}` : 'Select portfolio'}
- activeItem={activePortfolio}
- items={portfolios}
- onSelect={(portfolio) => router.push(`/projects/${portfolio.project.id}/portfolios/${portfolio.number}`)}
- onToggle={setOpen}
- isOpen={isOpen}
- />
- )
-}
-
-PortfolioSelector.propTypes = {
- activePortfolio: Portfolio,
-}
-
-export default PortfolioSelector
diff --git a/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js b/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js
deleted file mode 100644
index f2791b38..00000000
--- a/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useRouter } from 'next/router'
-import { useState } from 'react'
-import { useProjects, useProject } from '../../data/project'
-import { Project } from '../../shapes'
-import ContextSelector from './ContextSelector'
-
-function ProjectSelector() {
- const router = useRouter()
- const projectId = +router.query['project']
-
- const [isOpen, setOpen] = useState(false)
- const { data: activeProject } = useProject(+projectId)
- const { data: projects = [] } = useProjects({ enabled: isOpen })
-
- return (
- <ContextSelector
- id="project"
- type="app"
- toggleText={activeProject ? activeProject.name : 'Select project'}
- items={projects}
- onSelect={(project) => router.push(`/projects/${project.id}`)}
- onToggle={setOpen}
- isOpen={isOpen}
- isFullHeight
- />
- )
-}
-
-ProjectSelector.propTypes = {
- activeProject: Project,
-}
-
-export default ProjectSelector
diff --git a/opendc-web/opendc-web-ui/src/components/context/TopologySelector.js b/opendc-web/opendc-web-ui/src/components/context/TopologySelector.js
deleted file mode 100644
index 355d9f4b..00000000
--- a/opendc-web/opendc-web-ui/src/components/context/TopologySelector.js
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useRouter } from 'next/router'
-import { useState } from 'react'
-import { useTopologies } from '../../data/topology'
-import { Topology } from '../../shapes'
-import ContextSelector from './ContextSelector'
-
-function TopologySelector({ activeTopology }) {
- const router = useRouter()
-
- const [isOpen, setOpen] = useState(false)
- const { data: topologies = [] } = useTopologies(activeTopology?.project?.id, { enabled: isOpen })
-
- return (
- <ContextSelector
- id="topology"
- toggleText={activeTopology ? `Topology: ${activeTopology.name}` : 'Select topology'}
- activeItem={activeTopology}
- items={topologies}
- onSelect={(topology) => router.push(`/projects/${topology.project.id}/topologies/${topology.number}`)}
- onToggle={setOpen}
- isOpen={isOpen}
- />
- )
-}
-
-TopologySelector.propTypes = {
- activeTopology: Topology,
-}
-
-export default TopologySelector
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js b/opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js
deleted file mode 100644
index fd9a72d2..00000000
--- a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenario.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { PlusIcon } from '@patternfly/react-icons'
-import { Button } from '@patternfly/react-core'
-import { useState } from 'react'
-import { useNewScenario } from '../../data/project'
-import NewScenarioModal from './NewScenarioModal'
-
-function NewScenario({ projectId, portfolioId }) {
- const [isVisible, setVisible] = useState(false)
- const { mutate: addScenario } = useNewScenario()
-
- const onSubmit = (projectId, portfolioNumber, data) => {
- addScenario({ projectId, portfolioNumber, data })
- setVisible(false)
- }
-
- return (
- <>
- <Button icon={<PlusIcon />} isSmall onClick={() => setVisible(true)}>
- New Scenario
- </Button>
- <NewScenarioModal
- projectId={projectId}
- portfolioId={portfolioId}
- isOpen={isVisible}
- onSubmit={onSubmit}
- onCancel={() => setVisible(false)}
- />
- </>
- )
-}
-
-NewScenario.propTypes = {
- projectId: PropTypes.number,
- portfolioId: PropTypes.number,
-}
-
-export default NewScenario
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js b/opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js
deleted file mode 100644
index ed35c163..00000000
--- a/opendc-web/opendc-web-ui/src/components/portfolios/NewScenarioModal.js
+++ /dev/null
@@ -1,157 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useRef, useState } from 'react'
-import Modal from '../util/modals/Modal'
-import {
- Checkbox,
- Form,
- FormGroup,
- FormSection,
- FormSelect,
- FormSelectOption,
- NumberInput,
- TextInput,
-} from '@patternfly/react-core'
-import { useSchedulers, useTraces } from '../../data/experiments'
-import { useTopologies } from '../../data/topology'
-import { usePortfolio } from '../../data/project'
-
-function NewScenarioModal({ projectId, portfolioId, isOpen, onSubmit: onSubmitUpstream, onCancel: onCancelUpstream }) {
- const { data: portfolio } = usePortfolio(projectId, portfolioId)
- const { data: topologies = [] } = useTopologies(projectId, { enabled: isOpen })
- const { data: traces = [] } = useTraces({ enabled: isOpen })
- const { data: schedulers = [] } = useSchedulers({ enabled: isOpen })
-
- // eslint-disable-next-line no-unused-vars
- const [isSubmitted, setSubmitted] = useState(false)
- const [traceLoad, setTraceLoad] = useState(100)
- const [trace, setTrace] = useState(undefined)
- const [topology, setTopology] = useState(undefined)
- const [scheduler, setScheduler] = useState(undefined)
- const [failuresEnabled, setFailuresEnabled] = useState(false)
- const [opPhenEnabled, setOpPhenEnabled] = useState(false)
- const nameInput = useRef(null)
-
- const resetState = () => {
- setSubmitted(false)
- setTraceLoad(100)
- setTrace(undefined)
- setTopology(undefined)
- setScheduler(undefined)
- setFailuresEnabled(false)
- setOpPhenEnabled(false)
- nameInput.current.value = ''
- }
-
- const onSubmit = (event) => {
- setSubmitted(true)
-
- if (event) {
- event.preventDefault()
- }
-
- const name = nameInput.current.value
-
- onSubmitUpstream(portfolio.project.id, portfolio.number, {
- name,
- workload: {
- trace: trace || traces[0].id,
- samplingFraction: traceLoad / 100,
- },
- topology: topology || topologies[0].number,
- phenomena: {
- failures: failuresEnabled,
- interference: opPhenEnabled,
- },
- schedulerName: scheduler || schedulers[0],
- })
-
- resetState()
- return true
- }
- const onCancel = () => {
- onCancelUpstream()
- resetState()
- }
-
- return (
- <Modal title="New Scenario" isOpen={isOpen} onSubmit={onSubmit} onCancel={onCancel}>
- <Form onSubmit={onSubmit}>
- <FormGroup label="Name" fieldId="name" isRequired>
- <TextInput
- id="name"
- name="name"
- type="text"
- isDisabled={portfolio?.scenarios?.length === 0}
- defaultValue={portfolio?.scenarios?.length === 0 ? 'Base scenario' : ''}
- ref={nameInput}
- />
- </FormGroup>
- <FormSection title="Workload">
- <FormGroup label="Trace" fieldId="trace" isRequired>
- <FormSelect id="trace" name="trace" value={trace} onChange={setTrace}>
- {traces.map((trace) => (
- <FormSelectOption value={trace.id} key={trace.id} label={trace.name} />
- ))}
- </FormSelect>
- </FormGroup>
- <FormGroup label="Load Sampling Fraction" fieldId="trace-load" isRequired>
- <NumberInput
- name="trace-load"
- type="number"
- min={0}
- max={100}
- value={traceLoad}
- onMinus={() => setTraceLoad((load) => load - 1)}
- onPlus={() => setTraceLoad((load) => load + 1)}
- onChange={(e) => setTraceLoad(Number(e.target.value))}
- unit="%"
- />
- </FormGroup>
- </FormSection>
- <FormSection title="Topology">
- <FormGroup label="Topology" fieldId="topology" isRequired>
- <FormSelect id="topology" name="topology" value={topology} onChange={setTopology}>
- {topologies.map((topology) => (
- <FormSelectOption value={topology.number} key={topology.number} label={topology.name} />
- ))}
- </FormSelect>
- </FormGroup>
-
- <FormGroup label="Scheduler" fieldId="scheduler" isRequired>
- <FormSelect id="scheduler" name="scheduler" value={scheduler} onChange={setScheduler}>
- {schedulers.map((scheduler) => (
- <FormSelectOption value={scheduler} key={scheduler} label={scheduler} />
- ))}
- </FormSelect>
- </FormGroup>
- </FormSection>
- <FormSection title="Operational Phenomena">
- <Checkbox
- label="Failures"
- id="failures"
- name="failures"
- isChecked={failuresEnabled}
- onChange={() => setFailuresEnabled((e) => !e)}
- />
- <Checkbox
- label="Performance Interference"
- id="perf-interference"
- name="perf-interference"
- isChecked={opPhenEnabled}
- onChange={() => setOpPhenEnabled((e) => !e)}
- />
- </FormSection>
- </Form>
- </Modal>
- )
-}
-
-NewScenarioModal.propTypes = {
- projectId: PropTypes.number,
- portfolioId: PropTypes.number,
- isOpen: PropTypes.bool.isRequired,
- onSubmit: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired,
-}
-
-export default NewScenarioModal
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js b/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js
deleted file mode 100644
index e561b655..00000000
--- a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioOverview.js
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import {
- Card,
- CardActions,
- CardBody,
- CardHeader,
- CardTitle,
- Chip,
- ChipGroup,
- DescriptionList,
- DescriptionListDescription,
- DescriptionListGroup,
- DescriptionListTerm,
- Grid,
- GridItem,
- Skeleton,
-} from '@patternfly/react-core'
-import React from 'react'
-import { usePortfolio } from '../../data/project'
-import { METRIC_NAMES } from '../../util/available-metrics'
-import NewScenario from './NewScenario'
-import ScenarioTable from './ScenarioTable'
-
-function PortfolioOverview({ projectId, portfolioId }) {
- const { status, data: portfolio } = usePortfolio(projectId, portfolioId)
-
- return (
- <Grid hasGutter>
- <GridItem md={2}>
- <Card>
- <CardTitle>Details</CardTitle>
- <CardBody>
- <DescriptionList>
- <DescriptionListGroup>
- <DescriptionListTerm>Name</DescriptionListTerm>
- <DescriptionListDescription>
- {portfolio?.name ?? <Skeleton screenreaderText="Loading portfolio" />}
- </DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Scenarios</DescriptionListTerm>
- <DescriptionListDescription>
- {portfolio?.scenarios?.length ?? <Skeleton screenreaderText="Loading portfolio" />}
- </DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Metrics</DescriptionListTerm>
- <DescriptionListDescription>
- {portfolio ? (
- portfolio.targets.metrics.length > 0 ? (
- <ChipGroup>
- {portfolio.targets.metrics.map((metric) => (
- <Chip isReadOnly key={metric}>
- {METRIC_NAMES[metric]}
- </Chip>
- ))}
- </ChipGroup>
- ) : (
- 'No metrics enabled'
- )
- ) : (
- <Skeleton screenreaderText="Loading portfolio" />
- )}
- </DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Repeats per Scenario</DescriptionListTerm>
- <DescriptionListDescription>
- {portfolio?.targets?.repeats ?? <Skeleton screenreaderText="Loading portfolio" />}
- </DescriptionListDescription>
- </DescriptionListGroup>
- </DescriptionList>
- </CardBody>
- </Card>
- </GridItem>
- <GridItem md={6}>
- <Card>
- <CardHeader>
- <CardActions>
- <NewScenario projectId={projectId} portfolioId={portfolioId} />
- </CardActions>
- <CardTitle>Scenarios</CardTitle>
- </CardHeader>
- <CardBody>
- <ScenarioTable portfolio={portfolio} status={status} />
- </CardBody>
- </Card>
- </GridItem>
- </Grid>
- )
-}
-
-PortfolioOverview.propTypes = {
- projectId: PropTypes.number,
- portfolioId: PropTypes.number,
-}
-
-export default PortfolioOverview
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResultInfo.js b/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResultInfo.js
deleted file mode 100644
index dbfa928f..00000000
--- a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResultInfo.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { Tooltip } from '@patternfly/react-core'
-import { OutlinedQuestionCircleIcon } from '@patternfly/react-icons'
-import { METRIC_DESCRIPTIONS } from '../../util/available-metrics'
-
-function PortfolioResultInfo({ metric }) {
- return (
- <Tooltip position="top" content={<div>{METRIC_DESCRIPTIONS[metric]}</div>}>
- <OutlinedQuestionCircleIcon title="Metric information" />
- </Tooltip>
- )
-}
-
-PortfolioResultInfo.propTypes = {
- metric: PropTypes.string.isRequired,
-}
-
-export default PortfolioResultInfo
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js b/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js
deleted file mode 100644
index 62150fa7..00000000
--- a/opendc-web/opendc-web-ui/src/components/portfolios/PortfolioResults.js
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { mean, std } from 'mathjs'
-import React, { useMemo } from 'react'
-import PropTypes from 'prop-types'
-import { VictoryErrorBar } from 'victory-errorbar'
-import { METRIC_NAMES, METRIC_UNITS, AVAILABLE_METRICS } from '../../util/available-metrics'
-import {
- Bullseye,
- Card,
- CardActions,
- CardBody,
- CardHeader,
- CardTitle,
- EmptyState,
- EmptyStateBody,
- EmptyStateIcon,
- Grid,
- GridItem,
- Spinner,
- Title,
-} from '@patternfly/react-core'
-import { Chart, ChartAxis, ChartBar, ChartTooltip } from '@patternfly/react-charts'
-import { ErrorCircleOIcon, CubesIcon } from '@patternfly/react-icons'
-import { usePortfolio } from '../../data/project'
-import PortfolioResultInfo from './PortfolioResultInfo'
-import NewScenario from './NewScenario'
-
-function PortfolioResults({ projectId, portfolioId }) {
- const { status, data: portfolio } = usePortfolio(projectId, portfolioId)
- const scenarios = useMemo(() => portfolio?.scenarios ?? [], [portfolio])
-
- const label = ({ datum }) =>
- `${datum.x}: ${datum.y.toLocaleString()} ± ${datum.errorY.toLocaleString()} ${METRIC_UNITS[datum.metric]}`
- const selectedMetrics = new Set(portfolio?.targets?.metrics ?? [])
- const dataPerMetric = useMemo(() => {
- const dataPerMetric = {}
- AVAILABLE_METRICS.forEach((metric) => {
- dataPerMetric[metric] = scenarios
- .filter((scenario) => scenario.jobs && scenario.jobs[scenario.jobs.length - 1].results)
- .map((scenario) => {
- const job = scenario.jobs[scenario.jobs.length - 1]
- return {
- metric,
- x: scenario.name,
- y: mean(job.results[metric]),
- errorY: std(job.results[metric]),
- label,
- }
- })
- })
- return dataPerMetric
- }, [scenarios])
-
- const categories = useMemo(() => ({ x: scenarios.map((s) => s.name).reverse() }), [scenarios])
-
- if (status === 'loading') {
- return (
- <Bullseye>
- <EmptyState>
- <EmptyStateIcon variant="container" component={Spinner} />
- <Title size="lg" headingLevel="h4">
- Loading Results
- </Title>
- </EmptyState>
- </Bullseye>
- )
- } else if (status === 'error') {
- return (
- <Bullseye>
- <EmptyState>
- <EmptyStateIcon variant="container" component={ErrorCircleOIcon} />
- <Title size="lg" headingLevel="h4">
- Unable to connect
- </Title>
- <EmptyStateBody>
- There was an error retrieving data. Check your connection and try again.
- </EmptyStateBody>
- </EmptyState>
- </Bullseye>
- )
- } else if (scenarios.length === 0) {
- return (
- <Bullseye>
- <EmptyState>
- <EmptyStateIcon variant="container" component={CubesIcon} />
- <Title size="lg" headingLevel="h4">
- No results
- </Title>
- <EmptyStateBody>
- No results are currently available for this portfolio. Run a scenario to obtain simulation
- results.
- </EmptyStateBody>
- <NewScenario projectId={projectId} portfolioId={portfolioId} />
- </EmptyState>
- </Bullseye>
- )
- }
-
- return (
- <Grid hasGutter>
- {AVAILABLE_METRICS.map(
- (metric) =>
- selectedMetrics.has(metric) && (
- <GridItem xl={6} lg={12} key={metric}>
- <Card>
- <CardHeader>
- <CardActions>
- <PortfolioResultInfo metric={metric} />
- </CardActions>
- <CardTitle>{METRIC_NAMES[metric]}</CardTitle>
- </CardHeader>
- <CardBody>
- <Chart
- width={650}
- height={250}
- padding={{
- top: 10,
- bottom: 60,
- left: 130,
- }}
- domainPadding={25}
- >
- <ChartAxis />
- <ChartAxis
- dependentAxis
- showGrid
- label={METRIC_UNITS[metric]}
- fixLabelOverlap
- />
- <ChartBar
- categories={categories}
- data={dataPerMetric[metric]}
- labelComponent={<ChartTooltip constrainToVisibleArea />}
- barWidth={25}
- horizontal
- />
- <VictoryErrorBar
- categories={categories}
- data={dataPerMetric[metric]}
- errorY={(d) => d.errorY}
- labelComponent={<></>}
- horizontal
- />
- </Chart>
- </CardBody>
- </Card>
- </GridItem>
- )
- )}
- </Grid>
- )
-}
-
-PortfolioResults.propTypes = {
- projectId: PropTypes.number,
- portfolioId: PropTypes.number,
-}
-
-export default PortfolioResults
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js
deleted file mode 100644
index 99d83f64..00000000
--- a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioState.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { ClockIcon, CheckCircleIcon, ErrorCircleOIcon } from '@patternfly/react-icons'
-import { JobState } from '../../shapes'
-
-function ScenarioState({ state }) {
- switch (state) {
- case 'PENDING':
- case 'CLAIMED':
- return (
- <span>
- <ClockIcon color="blue" /> Queued
- </span>
- )
- case 'RUNNING':
- return (
- <span>
- <ClockIcon color="green" /> Running
- </span>
- )
- case 'FINISHED':
- return (
- <span>
- <CheckCircleIcon color="green" /> Finished
- </span>
- )
- case 'FAILED':
- return (
- <span>
- <ErrorCircleOIcon color="red" /> Failed
- </span>
- )
- }
-
- return 'Unknown'
-}
-
-ScenarioState.propTypes = {
- state: JobState.isRequired,
-}
-
-export default ScenarioState
diff --git a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js b/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
deleted file mode 100644
index b068d045..00000000
--- a/opendc-web/opendc-web-ui/src/components/portfolios/ScenarioTable.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { Bullseye } from '@patternfly/react-core'
-import Link from 'next/link'
-import { TableComposable, Thead, Tr, Th, Tbody, Td, ActionsColumn } from '@patternfly/react-table'
-import React from 'react'
-import { Portfolio, Status } from '../../shapes'
-import TableEmptyState from '../util/TableEmptyState'
-import ScenarioState from './ScenarioState'
-import { useDeleteScenario } from '../../data/project'
-
-function ScenarioTable({ portfolio, status }) {
- const { mutate: deleteScenario } = useDeleteScenario()
- const projectId = portfolio?.project?.id
- const scenarios = portfolio?.scenarios ?? []
-
- const actions = ({ number }) => [
- {
- title: 'Delete Scenario',
- onClick: () => deleteScenario({ projectId: projectId, number }),
- isDisabled: number === 0,
- },
- ]
-
- return (
- <TableComposable aria-label="Scenario List" variant="compact">
- <Thead>
- <Tr>
- <Th>Name</Th>
- <Th>Topology</Th>
- <Th>Trace</Th>
- <Th>State</Th>
- </Tr>
- </Thead>
- <Tbody>
- {scenarios.map((scenario) => (
- <Tr key={scenario.id}>
- <Td dataLabel="Name">{scenario.name}</Td>
- <Td dataLabel="Topology">
- {scenario.topology ? (
- <Link href={`/projects/${projectId}/topologies/${scenario.topology.number}`}>
- {scenario.topology.name}
- </Link>
- ) : (
- 'Unknown Topology'
- )}
- </Td>
- <Td dataLabel="Workload">{`${scenario.workload.trace.name} (${
- scenario.workload.samplingFraction * 100
- }%)`}</Td>
- <Td dataLabel="State">
- <ScenarioState state={scenario.jobs[scenario.jobs.length - 1].state} />
- </Td>
- <Td isActionCell>
- <ActionsColumn items={actions(scenario)} />
- </Td>
- </Tr>
- ))}
- {scenarios.length === 0 && (
- <Tr>
- <Td colSpan={4}>
- <Bullseye>
- <TableEmptyState
- status={status}
- loadingTitle="Loading Scenarios"
- emptyTitle="No scenarios"
- emptyText="You have not created any scenario for this portfolio yet. Click the New Scenario button to create one."
- />
- </Bullseye>
- </Td>
- </Tr>
- )}
- </Tbody>
- </TableComposable>
- )
-}
-
-ScenarioTable.propTypes = {
- portfolio: Portfolio,
- status: Status.isRequired,
-}
-
-export default ScenarioTable
diff --git a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js
deleted file mode 100644
index 5aaa56ac..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { ToggleGroup, ToggleGroupItem } from '@patternfly/react-core'
-import { filterPanel } from './FilterPanel.module.css'
-
-export const FILTERS = { SHOW_ALL: 'All Projects', SHOW_OWN: 'My Projects', SHOW_SHARED: 'Shared with me' }
-
-const FilterPanel = ({ onSelect, activeFilter = 'SHOW_ALL' }) => (
- <ToggleGroup className={`${filterPanel} pf-u-mb-sm`}>
- {Object.keys(FILTERS).map((filter) => (
- <ToggleGroupItem
- key={filter}
- onChange={() => activeFilter === filter || onSelect(filter)}
- isSelected={activeFilter === filter}
- text={FILTERS[filter]}
- />
- ))}
- </ToggleGroup>
-)
-
-FilterPanel.propTypes = {
- onSelect: PropTypes.func.isRequired,
- activeFilter: PropTypes.string,
-}
-
-export default FilterPanel
diff --git a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.css b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.css
deleted file mode 100644
index 15c36821..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.module.css
+++ /dev/null
@@ -1,7 +0,0 @@
-.filterPanel {
- display: flex;
-}
-
-.filterPanel > button {
- flex: 1 !important;
-}
diff --git a/opendc-web/opendc-web-ui/src/components/projects/NewPortfolio.js b/opendc-web/opendc-web-ui/src/components/projects/NewPortfolio.js
deleted file mode 100644
index aebcc3c9..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/NewPortfolio.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { PlusIcon } from '@patternfly/react-icons'
-import { Button } from '@patternfly/react-core'
-import { useState } from 'react'
-import { useNewPortfolio } from '../../data/project'
-import NewPortfolioModal from './NewPortfolioModal'
-
-function NewPortfolio({ projectId }) {
- const [isVisible, setVisible] = useState(false)
- const { mutate: addPortfolio } = useNewPortfolio()
-
- const onSubmit = (name, targets) => {
- addPortfolio({ projectId, name, targets })
- setVisible(false)
- }
-
- return (
- <>
- <Button icon={<PlusIcon />} isSmall onClick={() => setVisible(true)}>
- New Portfolio
- </Button>
- <NewPortfolioModal isOpen={isVisible} onSubmit={onSubmit} onCancel={() => setVisible(false)} />
- </>
- )
-}
-
-NewPortfolio.propTypes = {
- projectId: PropTypes.number,
-}
-
-export default NewPortfolio
diff --git a/opendc-web/opendc-web-ui/src/components/projects/NewPortfolioModal.js b/opendc-web/opendc-web-ui/src/components/projects/NewPortfolioModal.js
deleted file mode 100644
index ba4bc819..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/NewPortfolioModal.js
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React, { useRef, useState } from 'react'
-import {
- Form,
- FormGroup,
- FormSection,
- NumberInput,
- Select,
- SelectGroup,
- SelectOption,
- SelectVariant,
- TextInput,
-} from '@patternfly/react-core'
-import Modal from '../util/modals/Modal'
-import { METRIC_GROUPS, METRIC_NAMES } from '../../util/available-metrics'
-
-const NewPortfolioModal = ({ isOpen, onSubmit: onSubmitUpstream, onCancel: onUpstreamCancel }) => {
- const nameInput = useRef(null)
- const [repeats, setRepeats] = useState(1)
- const [isSelectOpen, setSelectOpen] = useState(false)
- const [selectedMetrics, setSelectedMetrics] = useState([])
-
- const [isSubmitted, setSubmitted] = useState(false)
- const [errors, setErrors] = useState({})
-
- const clearState = () => {
- setSubmitted(false)
- setErrors({})
- nameInput.current.value = ''
- setRepeats(1)
- setSelectOpen(false)
- setSelectedMetrics([])
- }
-
- const onSubmit = (event) => {
- setSubmitted(true)
-
- if (event) {
- event.preventDefault()
- }
-
- const name = nameInput.current.value
-
- if (!name) {
- setErrors({ name: true })
- return false
- } else {
- onSubmitUpstream(name, { metrics: selectedMetrics, repeats })
- }
-
- clearState()
- return false
- }
- const onCancel = () => {
- onUpstreamCancel()
- clearState()
- }
-
- const onSelect = (event, selection) => {
- if (selectedMetrics.includes(selection)) {
- setSelectedMetrics((metrics) => metrics.filter((item) => item !== selection))
- } else {
- setSelectedMetrics((metrics) => [...metrics, selection])
- }
- }
-
- return (
- <Modal title="New Portfolio" isOpen={isOpen} onSubmit={onSubmit} onCancel={onCancel}>
- <Form onSubmit={onSubmit}>
- <FormSection>
- <FormGroup
- label="Name"
- fieldId="name"
- isRequired
- validated={isSubmitted && errors.name ? 'error' : 'default'}
- helperTextInvalid="This field cannot be empty"
- >
- <TextInput
- name="name"
- id="name"
- type="text"
- isRequired
- ref={nameInput}
- placeholder="My Portfolio"
- />
- </FormGroup>
- </FormSection>
- <FormSection title="Targets" titleElement="h4">
- <FormGroup label="Metrics" fieldId="metrics">
- <Select
- variant={SelectVariant.typeaheadMulti}
- typeAheadAriaLabel="Select a metric"
- onToggle={() => setSelectOpen(!isSelectOpen)}
- onSelect={onSelect}
- onClear={() => setSelectedMetrics([])}
- selections={selectedMetrics}
- isOpen={isSelectOpen}
- placeholderText="Select a metric"
- menuAppendTo="parent"
- maxHeight="300px"
- chipGroupProps={{ numChips: 1 }}
- isGrouped
- >
- {Object.entries(METRIC_GROUPS).map(([group, metrics]) => (
- <SelectGroup label={group} key={group}>
- {metrics.map((metric) => (
- <SelectOption key={metric} value={metric}>
- {METRIC_NAMES[metric]}
- </SelectOption>
- ))}
- </SelectGroup>
- ))}
- </Select>
- </FormGroup>
- <FormGroup label="Repeats per Scenario" fieldId="repeats">
- <NumberInput
- id="repeats"
- inputName="repeats"
- type="number"
- value={repeats}
- onChange={(e) => setRepeats(Number(e.target.value))}
- onPlus={() => setRepeats((r) => r + 1)}
- onMinus={() => setRepeats((r) => r - 1)}
- min={1}
- />
- </FormGroup>
- </FormSection>
- </Form>
- </Modal>
- )
-}
-
-NewPortfolioModal.propTypes = {
- isOpen: PropTypes.bool.isRequired,
- onSubmit: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired,
-}
-
-export default NewPortfolioModal
diff --git a/opendc-web/opendc-web-ui/src/components/projects/NewTopology.js b/opendc-web/opendc-web-ui/src/components/projects/NewTopology.js
deleted file mode 100644
index 4c569c56..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/NewTopology.js
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { PlusIcon } from '@patternfly/react-icons'
-import { Button } from '@patternfly/react-core'
-import { useState } from 'react'
-import { useNewTopology } from '../../data/topology'
-import NewTopologyModal from './NewTopologyModal'
-
-function NewTopology({ projectId }) {
- const [isVisible, setVisible] = useState(false)
- const { mutate: addTopology } = useNewTopology()
-
- const onSubmit = (topology) => {
- addTopology(topology)
- setVisible(false)
- }
- return (
- <>
- <Button icon={<PlusIcon />} isSmall onClick={() => setVisible(true)}>
- New Topology
- </Button>
- <NewTopologyModal
- projectId={projectId}
- isOpen={isVisible}
- onSubmit={onSubmit}
- onCancel={() => setVisible(false)}
- />
- </>
- )
-}
-
-NewTopology.propTypes = {
- projectId: PropTypes.number,
-}
-
-export default NewTopology
diff --git a/opendc-web/opendc-web-ui/src/components/projects/NewTopologyModal.js b/opendc-web/opendc-web-ui/src/components/projects/NewTopologyModal.js
deleted file mode 100644
index 780ec034..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/NewTopologyModal.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import produce from 'immer'
-import PropTypes from 'prop-types'
-import React, { useRef, useState } from 'react'
-import { Form, FormGroup, FormSelect, FormSelectOption, TextInput } from '@patternfly/react-core'
-import { useTopologies } from '../../data/topology'
-import Modal from '../util/modals/Modal'
-
-const NewTopologyModal = ({ projectId, isOpen, onSubmit: onSubmitUpstream, onCancel: onCancelUpstream }) => {
- const nameInput = useRef(null)
- const [isSubmitted, setSubmitted] = useState(false)
- const [originTopology, setOriginTopology] = useState(-1)
- const [errors, setErrors] = useState({})
-
- const { data: topologies = [] } = useTopologies(projectId, { enabled: isOpen })
-
- const clearState = () => {
- if (nameInput.current) {
- nameInput.current.value = ''
- }
- setSubmitted(false)
- setOriginTopology(-1)
- setErrors({})
- }
-
- const onSubmit = (event) => {
- setSubmitted(true)
-
- if (event) {
- event.preventDefault()
- }
-
- const name = nameInput.current.value
-
- if (!name) {
- setErrors({ name: true })
- return false
- } else {
- const candidate = topologies.find((topology) => topology.id === originTopology) || { rooms: [] }
- const topology = produce(candidate, (draft) => {
- delete draft.project
- draft.projectId = projectId
- draft.name = name
- })
- onSubmitUpstream(topology)
- }
-
- clearState()
- return true
- }
-
- const onCancel = () => {
- onCancelUpstream()
- clearState()
- }
-
- return (
- <Modal title="New Topology" isOpen={isOpen} onSubmit={onSubmit} onCancel={onCancel}>
- <Form onSubmit={onSubmit}>
- <FormGroup
- label="Name"
- fieldId="name"
- isRequired
- validated={isSubmitted && errors.name ? 'error' : 'default'}
- helperTextInvalid="This field cannot be empty"
- >
- <TextInput id="name" name="name" type="text" isRequired ref={nameInput} />
- </FormGroup>
- <FormGroup label="Topology to duplicate" fieldId="origin" isRequired>
- <FormSelect
- id="origin"
- name="origin"
- value={originTopology}
- onChange={(v) => setOriginTopology(+v)}
- >
- <FormSelectOption value={-1} key={-1} label="None - start from scratch" />
- {topologies.map((topology) => (
- <FormSelectOption value={topology.id} key={topology.id} label={topology.name} />
- ))}
- </FormSelect>
- </FormGroup>
- </Form>
- </Modal>
- )
-}
-
-NewTopologyModal.propTypes = {
- projectId: PropTypes.number,
- isOpen: PropTypes.bool.isRequired,
- onSubmit: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired,
-}
-
-export default NewTopologyModal
diff --git a/opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js b/opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js
deleted file mode 100644
index 0afeaeaf..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/PortfolioTable.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { Bullseye } from '@patternfly/react-core'
-import PropTypes from 'prop-types'
-import Link from 'next/link'
-import { TableComposable, Thead, Tbody, Tr, Th, Td, ActionsColumn } from '@patternfly/react-table'
-import React from 'react'
-import TableEmptyState from '../util/TableEmptyState'
-import { usePortfolios, useDeletePortfolio } from '../../data/project'
-
-function PortfolioTable({ projectId }) {
- const { status, data: portfolios = [] } = usePortfolios(projectId)
- const { mutate: deletePortfolio } = useDeletePortfolio()
-
- const actions = (portfolio) => [
- {
- title: 'Delete Portfolio',
- onClick: () => deletePortfolio({ projectId, number: portfolio.number }),
- },
- ]
-
- return (
- <TableComposable aria-label="Portfolio List" variant="compact">
- <Thead>
- <Tr>
- <Th>Name</Th>
- <Th>Scenarios</Th>
- <Th>Metrics</Th>
- <Th>Repeats</Th>
- </Tr>
- </Thead>
- <Tbody>
- {portfolios.map((portfolio) => (
- <Tr key={portfolio.id}>
- <Td dataLabel="Name">
- <Link href={`/projects/${projectId}/portfolios/${portfolio.number}`}>{portfolio.name}</Link>
- </Td>
- <Td dataLabel="Scenarios">
- {portfolio.scenarios.length === 1
- ? '1 scenario'
- : `${portfolio.scenarios.length} scenarios`}
- </Td>
- <Td dataLabel="Metrics">
- {portfolio.targets.metrics.length === 1
- ? '1 metric'
- : `${portfolio.targets.metrics.length} metrics`}
- </Td>
- <Td dataLabel="Repeats">
- {portfolio.targets.repeats === 1 ? '1 repeat' : `${portfolio.targets.repeats} repeats`}
- </Td>
- <Td isActionCell>
- <ActionsColumn items={actions(portfolio)} />
- </Td>
- </Tr>
- ))}
- {portfolios.length === 0 && (
- <Tr>
- <Td colSpan={4}>
- <Bullseye>
- <TableEmptyState
- status={status}
- loadingTitle="Loading portfolios"
- emptyTitle="No portfolios"
- emptyText="You have not created any portfolio for this project yet. Click the New Portfolio button to create one."
- />
- </Bullseye>
- </Td>
- </Tr>
- )}
- </Tbody>
- </TableComposable>
- )
-}
-
-PortfolioTable.propTypes = {
- projectId: PropTypes.number,
-}
-
-export default PortfolioTable
diff --git a/opendc-web/opendc-web-ui/src/components/projects/ProjectCollection.js b/opendc-web/opendc-web-ui/src/components/projects/ProjectCollection.js
deleted file mode 100644
index a26fed46..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/ProjectCollection.js
+++ /dev/null
@@ -1,137 +0,0 @@
-import Link from 'next/link'
-import {
- Gallery,
- Bullseye,
- EmptyState,
- EmptyStateIcon,
- Card,
- CardTitle,
- CardActions,
- DropdownItem,
- CardHeader,
- Dropdown,
- KebabToggle,
- CardBody,
- CardHeaderMain,
- TextVariants,
- Text,
- TextContent,
- Tooltip,
- Button,
- Label,
-} from '@patternfly/react-core'
-import { PlusIcon, FolderIcon, TrashIcon } from '@patternfly/react-icons'
-import PropTypes from 'prop-types'
-import React, { useReducer, useMemo } from 'react'
-import { Project, Status } from '../../shapes'
-import { parseAndFormatDateTime } from '../../util/date-time'
-import { AUTH_DESCRIPTION_MAP, AUTH_ICON_MAP, AUTH_NAME_MAP } from '../../util/authorizations'
-import TableEmptyState from '../util/TableEmptyState'
-
-function ProjectCard({ project, onDelete }) {
- const [isKebabOpen, toggleKebab] = useReducer((t) => !t, false)
- const { id, role, name, updatedAt } = project
- const Icon = AUTH_ICON_MAP[role]
-
- return (
- <Card
- isCompact
- isRounded
- isFlat
- className="pf-u-min-height"
- style={{ '--pf-u-min-height--MinHeight': '175px' }}
- >
- <CardHeader className="pf-u-flex-grow-1">
- <CardHeaderMain className="pf-u-align-self-flex-start">
- <FolderIcon />
- </CardHeaderMain>
- <CardActions>
- <Tooltip content={AUTH_DESCRIPTION_MAP[role]}>
- <Label icon={<Icon />}>{AUTH_NAME_MAP[role]}</Label>
- </Tooltip>
- <Dropdown
- isPlain
- position="right"
- toggle={<KebabToggle className="pf-u-px-0" onToggle={toggleKebab} />}
- isOpen={isKebabOpen}
- dropdownItems={[
- <DropdownItem
- key="trash"
- onClick={() => {
- onDelete()
- toggleKebab()
- }}
- position="right"
- icon={<TrashIcon />}
- >
- Delete
- </DropdownItem>,
- ]}
- />
- </CardActions>
- </CardHeader>
- <CardTitle component={Link} className="pf-u-pb-0" href={`/projects/${id}`}>
- {name}
- </CardTitle>
- <CardBody isFilled={false}>
- <TextContent>
- <Text component={TextVariants.small}>Last modified {parseAndFormatDateTime(updatedAt)}</Text>
- </TextContent>
- </CardBody>
- </Card>
- )
-}
-
-function ProjectCollection({ status, projects, onDelete, onCreate, isFiltering }) {
- const sortedProjects = useMemo(() => {
- const res = [...projects]
- res.sort((a, b) => (new Date(a.updatedAt) < new Date(b.updatedAt) ? 1 : -1))
- return res
- }, [projects])
-
- if (sortedProjects.length === 0) {
- return (
- <TableEmptyState
- status={status}
- isFiltering={isFiltering}
- loadingTitle="Loading Projects"
- emptyTitle="No projects"
- emptyText="You have not created any projects yet. Create a new project to get started quickly."
- emptyAction={
- <Button icon={<PlusIcon />} onClick={onCreate}>
- Create Project
- </Button>
- }
- />
- )
- }
-
- return (
- <Gallery hasGutter aria-label="Available projects">
- {sortedProjects.map((project) => (
- <ProjectCard key={project.id} project={project} onDelete={() => onDelete(project)} />
- ))}
- <Card isCompact isFlat isRounded style={{ borderStyle: 'dotted' }}>
- <Bullseye>
- <EmptyState>
- <Button isBlock variant="link" onClick={onCreate}>
- <EmptyStateIcon icon={PlusIcon} />
- <br />
- Create Project
- </Button>
- </EmptyState>
- </Bullseye>
- </Card>
- </Gallery>
- )
-}
-
-ProjectCollection.propTypes = {
- status: Status.isRequired,
- isFiltering: PropTypes.bool,
- projects: PropTypes.arrayOf(Project).isRequired,
- onDelete: PropTypes.func,
- onCreate: PropTypes.func,
-}
-
-export default ProjectCollection
diff --git a/opendc-web/opendc-web-ui/src/components/projects/ProjectOverview.js b/opendc-web/opendc-web-ui/src/components/projects/ProjectOverview.js
deleted file mode 100644
index 3e1656f6..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/ProjectOverview.js
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import {
- Card,
- CardActions,
- CardBody,
- CardHeader,
- CardTitle,
- DescriptionList,
- DescriptionListDescription,
- DescriptionListGroup,
- DescriptionListTerm,
- Grid,
- GridItem,
- Skeleton,
-} from '@patternfly/react-core'
-import NewTopology from './NewTopology'
-import TopologyTable from './TopologyTable'
-import NewPortfolio from './NewPortfolio'
-import PortfolioTable from './PortfolioTable'
-import { useProject } from '../../data/project'
-
-function ProjectOverview({ projectId }) {
- const { data: project } = useProject(projectId)
-
- return (
- <Grid hasGutter>
- <GridItem md={2}>
- <Card>
- <CardTitle>Details</CardTitle>
- <CardBody>
- <DescriptionList>
- <DescriptionListGroup>
- <DescriptionListTerm>Name</DescriptionListTerm>
- <DescriptionListDescription>
- {project?.name ?? <Skeleton screenreaderText="Loading project" />}
- </DescriptionListDescription>
- </DescriptionListGroup>
- </DescriptionList>
- </CardBody>
- </Card>
- </GridItem>
- <GridItem md={5}>
- <Card>
- <CardHeader>
- <CardActions>
- <NewTopology projectId={projectId} />
- </CardActions>
- <CardTitle>Topologies</CardTitle>
- </CardHeader>
- <CardBody>
- <TopologyTable projectId={projectId} />
- </CardBody>
- </Card>
- </GridItem>
- <GridItem md={5}>
- <Card>
- <CardHeader>
- <CardActions>
- <NewPortfolio projectId={projectId} />
- </CardActions>
- <CardTitle>Portfolios</CardTitle>
- </CardHeader>
- <CardBody>
- <PortfolioTable projectId={projectId} />
- </CardBody>
- </Card>
- </GridItem>
- </Grid>
- )
-}
-
-ProjectOverview.propTypes = {
- projectId: PropTypes.number,
-}
-
-export default ProjectOverview
diff --git a/opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js b/opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js
deleted file mode 100644
index 1c2c4f04..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/TopologyTable.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { Bullseye, AlertGroup, Alert, AlertVariant, AlertActionCloseButton } from '@patternfly/react-core'
-import PropTypes from 'prop-types'
-import Link from 'next/link'
-import { Tr, Th, Thead, Td, ActionsColumn, Tbody, TableComposable } from '@patternfly/react-table'
-import React, { useState } from 'react'
-import TableEmptyState from '../util/TableEmptyState'
-import { parseAndFormatDateTime } from '../../util/date-time'
-import { useTopologies, useDeleteTopology } from '../../data/topology'
-
-function TopologyTable({ projectId }) {
- const [error, setError] = useState('')
-
- const { status, data: topologies = [] } = useTopologies(projectId)
- const { mutate: deleteTopology } = useDeleteTopology({
- onError: (error) => setError(error),
- })
-
- const actions = ({ number }) => [
- {
- title: 'Delete Topology',
- onClick: () => deleteTopology({ projectId, number }),
- isDisabled: number === 0,
- },
- ]
-
- return (
- <>
- <AlertGroup isToast>
- {error && (
- <Alert
- isLiveRegion
- variant={AlertVariant.danger}
- title={error}
- actionClose={
- <AlertActionCloseButton
- title={error}
- variantLabel="danger alert"
- onClose={() => setError(null)}
- />
- }
- />
- )}
- </AlertGroup>
- <TableComposable aria-label="Topology List" variant="compact">
- <Thead>
- <Tr>
- <Th>Name</Th>
- <Th>Rooms</Th>
- <Th>Last Edited</Th>
- </Tr>
- </Thead>
- <Tbody>
- {topologies.map((topology) => (
- <Tr key={topology.id}>
- <Td dataLabel="Name">
- <Link href={`/projects/${projectId}/topologies/${topology.number}`}>
- {topology.name}
- </Link>
- </Td>
- <Td dataLabel="Rooms">
- {topology.rooms.length === 1 ? '1 room' : `${topology.rooms.length} rooms`}
- </Td>
- <Td dataLabel="Last Edited">{parseAndFormatDateTime(topology.updatedAt)}</Td>
- <Td isActionCell>
- <ActionsColumn items={actions(topology)} />
- </Td>
- </Tr>
- ))}
- {topologies.length === 0 && (
- <Tr>
- <Td colSpan={3}>
- <Bullseye>
- <TableEmptyState
- status={status}
- loadingTitle="Loading topologies"
- emptyTitle="No topologies"
- emptyText="You have not created any topology for this project yet. Click the New Topology button to create one."
- />
- </Bullseye>
- </Td>
- </Tr>
- )}
- </Tbody>
- </TableComposable>
- </>
- )
-}
-
-TopologyTable.propTypes = {
- projectId: PropTypes.number,
-}
-
-export default TopologyTable
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js b/opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js
deleted file mode 100644
index 7f7b4171..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/RoomTable.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import { Button, Bullseye } from '@patternfly/react-core'
-import PropTypes from 'prop-types'
-import React from 'react'
-import { useDispatch } from 'react-redux'
-import { useTopology } from '../../data/topology'
-import { Tr, Th, Thead, TableComposable, Td, ActionsColumn, Tbody } from '@patternfly/react-table'
-import { deleteRoom } from '../../redux/actions/topology/room'
-import TableEmptyState from '../util/TableEmptyState'
-
-function RoomTable({ projectId, topologyId, onSelect }) {
- const dispatch = useDispatch()
- const { status, data: topology } = useTopology(projectId, topologyId)
- const onDelete = (room) => dispatch(deleteRoom(room.id))
- const actions = (room) => [
- {
- title: 'Delete room',
- onClick: () => onDelete(room),
- },
- ]
-
- return (
- <TableComposable aria-label="Room list" variant="compact">
- <Thead>
- <Tr>
- <Th>Name</Th>
- <Th>Tiles</Th>
- <Th>Racks</Th>
- </Tr>
- </Thead>
- <Tbody>
- {topology?.rooms.map((room) => {
- const tileCount = room.tiles.length
- const rackCount = room.tiles.filter((tile) => tile.rack).length
- return (
- <Tr key={room.id}>
- <Td dataLabel="Name">
- <Button variant="link" isInline onClick={() => onSelect(room)}>
- {room.name}
- </Button>
- </Td>
- <Td dataLabel="Tiles">{tileCount === 1 ? '1 tile' : `${tileCount} tiles`}</Td>
- <Td dataLabel="Racks">{rackCount === 1 ? '1 rack' : `${rackCount} racks`}</Td>
- <Td isActionCell>
- <ActionsColumn items={actions(room)} />
- </Td>
- </Tr>
- )
- })}
- {topology?.rooms.length === 0 && (
- <Tr>
- <Td colSpan={4}>
- <Bullseye>
- <TableEmptyState
- status={status}
- loadingTitle="Loading Rooms"
- emptyTitle="No rooms"
- emptyText="There are currently no rooms in this topology. Open the Floor Plan to create a room"
- />
- </Bullseye>
- </Td>
- </Tr>
- )}
- </Tbody>
- </TableComposable>
- )
-}
-
-RoomTable.propTypes = {
- projectId: PropTypes.number,
- topologyId: PropTypes.number,
- onSelect: PropTypes.func,
-}
-
-export default RoomTable
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js b/opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js
deleted file mode 100644
index ff583750..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/TopologyMap.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React, { useState, useRef } from 'react'
-import {
- Bullseye,
- Drawer,
- DrawerContent,
- DrawerContentBody,
- EmptyState,
- EmptyStateIcon,
- Spinner,
- Title,
-} from '@patternfly/react-core'
-import MapStage from './map/MapStage'
-import Collapse from './map/controls/Collapse'
-import { useSelector } from 'react-redux'
-import TopologySidebar from './sidebar/TopologySidebar'
-
-function TopologyMap() {
- const topologyIsLoading = useSelector((state) => !state.topology.root)
- const interactionLevel = useSelector((state) => state.interactionLevel)
-
- const [isExpanded, setExpanded] = useState(true)
- const panelContent = <TopologySidebar interactionLevel={interactionLevel} onClose={() => setExpanded(false)} />
-
- const hotkeysRef = useRef()
-
- return topologyIsLoading ? (
- <Bullseye>
- <EmptyState>
- <EmptyStateIcon variant="container" component={Spinner} />
- <Title size="lg" headingLevel="h4">
- Loading Topology
- </Title>
- </EmptyState>
- </Bullseye>
- ) : (
- <Drawer isExpanded={isExpanded}>
- <DrawerContent panelContent={panelContent}>
- <DrawerContentBody style={{ position: 'relative' }}>
- <MapStage hotkeysRef={hotkeysRef} />
- <Collapse onClick={() => setExpanded(true)} />
- </DrawerContentBody>
- </DrawerContent>
- </Drawer>
- )
-}
-
-export default TopologyMap
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/TopologyOverview.js b/opendc-web/opendc-web-ui/src/components/topologies/TopologyOverview.js
deleted file mode 100644
index f8ee4990..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/TopologyOverview.js
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import {
- Card,
- CardBody,
- CardTitle,
- DescriptionList,
- DescriptionListDescription,
- DescriptionListGroup,
- DescriptionListTerm,
- Grid,
- GridItem,
- Skeleton,
-} from '@patternfly/react-core'
-import React from 'react'
-import { useTopology } from '../../data/topology'
-import { parseAndFormatDateTime } from '../../util/date-time'
-import RoomTable from './RoomTable'
-
-function TopologyOverview({ projectId, topologyNumber, onSelect }) {
- const { data: topology } = useTopology(projectId, topologyNumber)
- return (
- <Grid hasGutter>
- <GridItem md={2}>
- <Card>
- <CardTitle>Details</CardTitle>
- <CardBody>
- <DescriptionList>
- <DescriptionListGroup>
- <DescriptionListTerm>Name</DescriptionListTerm>
- <DescriptionListDescription>
- {topology?.name ?? <Skeleton screenreaderText="Loading topology" />}
- </DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Last edited</DescriptionListTerm>
- <DescriptionListDescription>
- {topology ? (
- parseAndFormatDateTime(topology.updatedAt)
- ) : (
- <Skeleton screenreaderText="Loading topology" />
- )}
- </DescriptionListDescription>
- </DescriptionListGroup>
- </DescriptionList>
- </CardBody>
- </Card>
- </GridItem>
- <GridItem md={5}>
- <Card>
- <CardTitle>Rooms</CardTitle>
- <CardBody>
- <RoomTable
- projectId={projectId}
- topologyId={topologyNumber}
- onSelect={(room) => onSelect('room', room)}
- />
- </CardBody>
- </Card>
- </GridItem>
- </Grid>
- )
-}
-
-TopologyOverview.propTypes = {
- projectId: PropTypes.number,
- topologyNumber: PropTypes.number,
- onSelect: PropTypes.func,
-}
-
-export default TopologyOverview
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/GrayContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/GrayContainer.js
deleted file mode 100644
index ccf637e5..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/GrayContainer.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { useDispatch } from 'react-redux'
-import { goDownOneInteractionLevel } from '../../../redux/actions/interaction-level'
-import GrayLayer from './elements/GrayLayer'
-
-function GrayContainer() {
- const dispatch = useDispatch()
- const onClick = () => dispatch(goDownOneInteractionLevel())
- return <GrayLayer onClick={onClick} />
-}
-
-export default GrayContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/MapConstants.js b/opendc-web/opendc-web-ui/src/components/topologies/map/MapConstants.js
deleted file mode 100644
index 4c3b2757..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/MapConstants.js
+++ /dev/null
@@ -1,25 +0,0 @@
-export const MAP_SIZE = 50
-export const TILE_SIZE_IN_PIXELS = 100
-export const TILE_SIZE_IN_METERS = 0.5
-export const MAP_SIZE_IN_PIXELS = MAP_SIZE * TILE_SIZE_IN_PIXELS
-
-export const OBJECT_MARGIN_IN_PIXELS = TILE_SIZE_IN_PIXELS / 5
-export const TILE_PLUS_MARGIN_IN_PIXELS = TILE_SIZE_IN_PIXELS / 3
-export const OBJECT_SIZE_IN_PIXELS = TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS * 2
-
-export const GRID_LINE_WIDTH_IN_PIXELS = 2
-export const WALL_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 16
-export const OBJECT_BORDER_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 16
-export const TILE_PLUS_WIDTH_IN_PIXELS = TILE_SIZE_IN_PIXELS / 10
-
-export const RACK_FILL_ICON_WIDTH = OBJECT_SIZE_IN_PIXELS / 3
-export const RACK_FILL_ICON_OPACITY = 0.8
-
-export const MAP_MOVE_PIXELS_PER_EVENT = 20
-export const MAP_SCALE_PER_EVENT = 1.1
-export const MAP_MIN_SCALE = 0.5
-export const MAP_MAX_SCALE = 1.5
-
-export const MAX_NUM_UNITS_PER_MACHINE = 6
-export const DEFAULT_RACK_SLOT_CAPACITY = 42
-export const DEFAULT_RACK_POWER_CAPACITY = 10000
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js b/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js
deleted file mode 100644
index e2b626ec..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import React, { useRef, useState } from 'react'
-import PropTypes from 'prop-types'
-import { useHotkeys } from 'react-hotkeys-hook'
-import { Stage } from 'react-konva'
-import { MAP_MAX_SCALE, MAP_MIN_SCALE, MAP_MOVE_PIXELS_PER_EVENT, MAP_SCALE_PER_EVENT } from './MapConstants'
-import useResizeObserver from 'use-resize-observer'
-import { mapContainer } from './MapStage.module.css'
-import MapLayer from './layers/MapLayer'
-import RoomHoverLayer from './layers/RoomHoverLayer'
-import ObjectHoverLayer from './layers/ObjectHoverLayer'
-import ScaleIndicator from './controls/ScaleIndicator'
-import Toolbar from './controls/Toolbar'
-
-function MapStage({ hotkeysRef }) {
- const stageRef = useRef(null)
- const { width = 500, height = 500 } = useResizeObserver({ ref: stageRef.current?.attrs?.container })
- const [[x, y], setPos] = useState([0, 0])
- const [scale, setScale] = useState(1)
-
- const clampScale = (target) => Math.min(Math.max(target, MAP_MIN_SCALE), MAP_MAX_SCALE)
- const moveWithDelta = (deltaX, deltaY) => setPos(([x, y]) => [x + deltaX, y + deltaY])
-
- const onZoom = (e) => {
- e.evt.preventDefault()
-
- const stage = stageRef.current.getStage()
- const oldScale = scale
-
- const pointer = stage.getPointerPosition()
- const mousePointTo = {
- x: (pointer.x - x) / oldScale,
- y: (pointer.y - y) / oldScale,
- }
-
- const newScale = clampScale(e.evt.deltaY > 0 ? oldScale * MAP_SCALE_PER_EVENT : oldScale / MAP_SCALE_PER_EVENT)
-
- setScale(newScale)
- setPos([pointer.x - mousePointTo.x * newScale, pointer.y - mousePointTo.y * newScale])
- }
- const onZoomButton = (zoomIn) =>
- setScale((scale) => clampScale(zoomIn ? scale * MAP_SCALE_PER_EVENT : scale / MAP_SCALE_PER_EVENT))
- const onDragEnd = (e) => setPos([e.target.x(), e.target.y()])
- const onExport = () => {
- const download = document.createElement('a')
- download.href = stageRef.current.getStage().toDataURL()
- download.download = 'opendc-canvas-export-' + Date.now() + '.png'
- download.click()
- }
-
- useHotkeys('left, a', () => moveWithDelta(MAP_MOVE_PIXELS_PER_EVENT, 0), { element: hotkeysRef.current })
- useHotkeys('right, d', () => moveWithDelta(-MAP_MOVE_PIXELS_PER_EVENT, 0), { element: hotkeysRef.current })
- useHotkeys('up, w', () => moveWithDelta(0, MAP_MOVE_PIXELS_PER_EVENT), { element: hotkeysRef.current })
- useHotkeys('down, s', () => moveWithDelta(0, -MAP_MOVE_PIXELS_PER_EVENT), { element: hotkeysRef.current })
-
- return (
- <>
- <Stage
- className={mapContainer}
- ref={stageRef}
- onWheel={onZoom}
- onDragEnd={onDragEnd}
- draggable
- width={width}
- height={height}
- scale={{ x: scale, y: scale }}
- x={x}
- y={y}
- >
- <MapLayer />
- <RoomHoverLayer />
- <ObjectHoverLayer />
- </Stage>
- <ScaleIndicator scale={scale} />
- <Toolbar onZoom={onZoomButton} onExport={onExport} />
- </>
- )
-}
-
-MapStage.propTypes = {
- hotkeysRef: PropTypes.object.isRequired,
-}
-
-export default MapStage
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.module.css b/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.module.css
deleted file mode 100644
index 47c3dde2..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/MapStage.module.css
+++ /dev/null
@@ -1,29 +0,0 @@
-/*!
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-.mapContainer {
- background-color: var(--pf-global--Color--light-200);
- position: relative;
- display: flex;
- width: 100%;
- height: 100%;
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/RackContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/RackContainer.js
deleted file mode 100644
index 14449a91..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/RackContainer.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { useSelector } from 'react-redux'
-import { Tile } from '../../../shapes'
-import RackGroup from './groups/RackGroup'
-
-function RackContainer({ tile }) {
- const interactionLevel = useSelector((state) => state.interactionLevel)
- return <RackGroup interactionLevel={interactionLevel} tile={tile} />
-}
-
-RackContainer.propTypes = {
- tile: Tile,
-}
-
-export default RackContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/RackEnergyFillContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/RackEnergyFillContainer.js
deleted file mode 100644
index a1ca7426..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/RackEnergyFillContainer.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { useSelector } from 'react-redux'
-import RackFillBar from './elements/RackFillBar'
-
-function RackSpaceFillContainer({ rackId, ...props }) {
- const fillFraction = useSelector((state) => {
- const rack = state.topology.racks[rackId]
- if (!rack) {
- return 0
- }
-
- const { machines, cpus, gpus, memories, storages } = state.topology
- let energyConsumptionTotal = 0
-
- for (const machineId of rack.machines) {
- if (!machineId) {
- continue
- }
- const machine = machines[machineId]
- machine.cpus.forEach((id) => (energyConsumptionTotal += cpus[id].energyConsumptionW))
- machine.gpus.forEach((id) => (energyConsumptionTotal += gpus[id].energyConsumptionW))
- machine.memories.forEach((id) => (energyConsumptionTotal += memories[id].energyConsumptionW))
- machine.storages.forEach((id) => (energyConsumptionTotal += storages[id].energyConsumptionW))
- }
-
- return Math.min(1, energyConsumptionTotal / rack.powerCapacityW)
- })
- return <RackFillBar {...props} type="energy" fillFraction={fillFraction} />
-}
-
-RackSpaceFillContainer.propTypes = {
- rackId: PropTypes.string.isRequired,
-}
-
-export default RackSpaceFillContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/RackSpaceFillContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/RackSpaceFillContainer.js
deleted file mode 100644
index 2039a9d3..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/RackSpaceFillContainer.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { useSelector } from 'react-redux'
-import RackFillBar from './elements/RackFillBar'
-
-function RackSpaceFillContainer({ rackId, ...props }) {
- const rack = useSelector((state) => state.topology.racks[rackId])
-
- if (!rack) {
- return null
- }
-
- return <RackFillBar {...props} type="space" fillFraction={rack.machines.length / rack.capacity} />
-}
-
-RackSpaceFillContainer.propTypes = {
- rackId: PropTypes.string.isRequired,
-}
-
-export default RackSpaceFillContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/RoomContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/RoomContainer.js
deleted file mode 100644
index 76785bea..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/RoomContainer.js
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { goFromBuildingToRoom } from '../../../redux/actions/interaction-level'
-import RoomGroup from './groups/RoomGroup'
-
-function RoomContainer({ roomId, ...props }) {
- const interactionLevel = useSelector((state) => state.interactionLevel)
- const currentRoomInConstruction = useSelector((state) => state.construction.currentRoomInConstruction)
- const room = useSelector((state) => state.topology.rooms[roomId])
- const dispatch = useDispatch()
-
- if (!room) {
- return null
- }
-
- return (
- <RoomGroup
- {...props}
- interactionLevel={interactionLevel}
- currentRoomInConstruction={currentRoomInConstruction}
- room={room}
- onClick={() => dispatch(goFromBuildingToRoom(roomId))}
- />
- )
-}
-
-RoomContainer.propTypes = {
- roomId: PropTypes.string,
-}
-
-export default RoomContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/TileContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/TileContainer.js
deleted file mode 100644
index 0788b894..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/TileContainer.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { useDispatch, useSelector } from 'react-redux'
-import { goFromRoomToRack } from '../../../redux/actions/interaction-level'
-import TileGroup from './groups/TileGroup'
-
-function TileContainer({ tileId, ...props }) {
- const interactionLevel = useSelector((state) => state.interactionLevel)
- const dispatch = useDispatch()
- const tile = useSelector((state) => state.topology.tiles[tileId])
-
- if (!tile) {
- return null
- }
-
- const onClick = (tile) => {
- if (tile.rack) {
- dispatch(goFromRoomToRack(tile.id))
- }
- }
- return <TileGroup {...props} onClick={onClick} tile={tile} interactionLevel={interactionLevel} />
-}
-
-TileContainer.propTypes = {
- tileId: PropTypes.string.isRequired,
-}
-
-export default TileContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/TopologyContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/TopologyContainer.js
deleted file mode 100644
index cc0d46b3..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/TopologyContainer.js
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { useSelector } from 'react-redux'
-import TopologyGroup from './groups/TopologyGroup'
-
-function TopologyContainer() {
- const topology = useSelector((state) => state.topology.root)
- const interactionLevel = useSelector((state) => state.interactionLevel)
-
- return <TopologyGroup topology={topology} interactionLevel={interactionLevel} />
-}
-
-export default TopologyContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/WallContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/WallContainer.js
deleted file mode 100644
index 106d8d3d..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/WallContainer.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import PropTypes from 'prop-types'
-import { useSelector } from 'react-redux'
-import WallGroup from './groups/WallGroup'
-
-function WallContainer({ roomId, ...props }) {
- const tiles = useSelector((state) => {
- return state.topology.rooms[roomId]?.tiles.map((tileId) => state.topology.tiles[tileId]) ?? []
- })
- return <WallGroup {...props} tiles={tiles} />
-}
-
-WallContainer.propTypes = {
- roomId: PropTypes.string.isRequired,
-}
-
-export default WallContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.js b/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.js
deleted file mode 100644
index 931ded94..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { ChevronLeftIcon } from '@patternfly/react-icons'
-import { collapseContainer } from './Collapse.module.css'
-import { Button } from '@patternfly/react-core'
-
-function Collapse({ onClick }) {
- return (
- <div className={collapseContainer}>
- <Button variant="tertiary" onClick={onClick}>
- <ChevronLeftIcon />
- </Button>
- </div>
- )
-}
-
-Collapse.propTypes = {
- onClick: PropTypes.func,
-}
-
-export default Collapse
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.module.css b/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.module.css
deleted file mode 100644
index 70fd465f..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Collapse.module.css
+++ /dev/null
@@ -1,55 +0,0 @@
-/*!
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-.collapseContainer {
- position: absolute;
- right: var(--pf-global--spacer--xs);
- top: 0;
- bottom: 10%;
- margin: auto 0;
- height: 50px;
-}
-
-.collapseContainer > button:global(.pf-m-tertiary) {
- height: 100%;
- padding: 2px;
-
- margin-right: var(--pf-global--spacer--xs);
- margin-top: var(--pf-global--spacer--xs);
- background-color: var(--pf-global--BackgroundColor--100);
- border: none;
- border-radius: var(--pf-global--BorderRadius--sm);
- box-shadow: var(--pf-global--BoxShadow--sm);
-}
-
-.collapseContainer > button:global(.pf-m-tertiary):not(:global(.pf-m-disabled)) {
- background-color: var(--pf-global--BackgroundColor--100);
-}
-
-.collapseContainer > button:global(.pf-m-tertiary):after {
- display: none;
-}
-
-.collapseContainer > button:global(.pf-m-tertiary):hover {
- border: none;
- box-shadow: var(--pf-global--BoxShadow--md);
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.js b/opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.js
deleted file mode 100644
index 3ec893fb..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { TILE_SIZE_IN_METERS, TILE_SIZE_IN_PIXELS } from '../MapConstants'
-import { scaleIndicator } from './ScaleIndicator.module.css'
-
-function ScaleIndicator({ scale }) {
- return (
- <div className={scaleIndicator} style={{ width: TILE_SIZE_IN_PIXELS * scale }}>
- {TILE_SIZE_IN_METERS}m
- </div>
- )
-}
-
-ScaleIndicator.propTypes = {
- scale: PropTypes.number.isRequired,
-}
-
-export default ScaleIndicator
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.module.css b/opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.module.css
deleted file mode 100644
index f19e0ff2..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/ScaleIndicator.module.css
+++ /dev/null
@@ -1,10 +0,0 @@
-.scaleIndicator {
- position: absolute;
- right: 10px;
- bottom: 10px;
- z-index: 50;
-
- border: solid 2px #212529;
- border-top: none;
- border-left: none;
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.js b/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.js
deleted file mode 100644
index 00aaf3e1..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { control, toolBar } from './Toolbar.module.css'
-import { Button } from '@patternfly/react-core'
-import { SearchPlusIcon, SearchMinusIcon, CameraIcon } from '@patternfly/react-icons'
-
-function Toolbar({ onZoom, onExport }) {
- return (
- <div className={toolBar}>
- <Button variant="tertiary" title="Zoom in" onClick={() => onZoom(true)} className={control}>
- <SearchPlusIcon />
- </Button>
- <Button variant="tertiary" title="Zoom out" onClick={() => onZoom(false)} className={control}>
- <SearchMinusIcon />
- </Button>
- <Button
- variant="tertiary"
- title="Export Canvas to PNG Image"
- onClick={() => onExport()}
- className={control}
- >
- <CameraIcon />
- </Button>
- </div>
- )
-}
-
-Toolbar.propTypes = {
- onZoom: PropTypes.func,
- onExport: PropTypes.func,
-}
-
-export default Toolbar
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.module.css b/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.module.css
deleted file mode 100644
index 007389da..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/controls/Toolbar.module.css
+++ /dev/null
@@ -1,27 +0,0 @@
-.toolBar {
- position: absolute;
- bottom: var(--pf-global--spacer--md);
- left: var(--pf-global--spacer--xl);
-}
-
-.control:global(.pf-m-tertiary) {
- margin-right: var(--pf-global--spacer--xs);
- margin-top: var(--pf-global--spacer--xs);
- background-color: var(--pf-global--BackgroundColor--100);
- border: none;
- border-radius: var(--pf-global--BorderRadius--sm);
- box-shadow: var(--pf-global--BoxShadow--sm);
-}
-
-.control:global(.pf-m-tertiary):not(:global(.pf-m-disabled)) {
- background-color: var(--pf-global--BackgroundColor--100);
-}
-
-.control:global(.pf-m-tertiary):after {
- display: none;
-}
-
-.control:global(.pf-m-tertiary):hover {
- border: none;
- box-shadow: var(--pf-global--BoxShadow--md);
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/Backdrop.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/Backdrop.js
deleted file mode 100644
index 93037b51..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/Backdrop.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react'
-import { Rect } from 'react-konva'
-import { BACKDROP_COLOR } from '../../../../util/colors'
-import { MAP_SIZE_IN_PIXELS } from '../MapConstants'
-
-function Backdrop() {
- return <Rect x={0} y={0} width={MAP_SIZE_IN_PIXELS} height={MAP_SIZE_IN_PIXELS} fill={BACKDROP_COLOR} />
-}
-
-export default Backdrop
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/GrayLayer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/GrayLayer.js
deleted file mode 100644
index 08c687f6..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/GrayLayer.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Rect } from 'react-konva'
-import { GRAYED_OUT_AREA_COLOR } from '../../../../util/colors'
-import { MAP_SIZE_IN_PIXELS } from '../MapConstants'
-
-function GrayLayer({ onClick }) {
- return (
- <Rect
- x={0}
- y={0}
- width={MAP_SIZE_IN_PIXELS}
- height={MAP_SIZE_IN_PIXELS}
- fill={GRAYED_OUT_AREA_COLOR}
- onClick={onClick}
- />
- )
-}
-
-GrayLayer.propTypes = {
- onClick: PropTypes.func,
-}
-
-export default GrayLayer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/HoverTile.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/HoverTile.js
deleted file mode 100644
index 20c2c6d1..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/HoverTile.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Rect } from 'react-konva'
-import { ROOM_HOVER_INVALID_COLOR, ROOM_HOVER_VALID_COLOR } from '../../../../util/colors'
-import { TILE_SIZE_IN_PIXELS } from '../MapConstants'
-
-function HoverTile({ x, y, isValid, scale = 1, onClick }) {
- return (
- <Rect
- x={x}
- y={y}
- scaleX={scale}
- scaleY={scale}
- width={TILE_SIZE_IN_PIXELS}
- height={TILE_SIZE_IN_PIXELS}
- fill={isValid ? ROOM_HOVER_VALID_COLOR : ROOM_HOVER_INVALID_COLOR}
- onClick={onClick}
- />
- )
-}
-
-HoverTile.propTypes = {
- x: PropTypes.number.isRequired,
- y: PropTypes.number.isRequired,
- isValid: PropTypes.bool.isRequired,
- scale: PropTypes.number,
- onClick: PropTypes.func.isRequired,
-}
-
-export default HoverTile
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/ImageComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/ImageComponent.js
deleted file mode 100644
index fdae53f2..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/ImageComponent.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useEffect, useState } from 'react'
-import { Image } from 'react-konva'
-
-const imageCaches = {}
-
-function ImageComponent({ src, x, y, width, height, opacity }) {
- const [image, setImage] = useState(null)
-
- useEffect(() => {
- if (imageCaches[src]) {
- setImage(imageCaches[src])
- return
- }
-
- const image = new window.Image()
- image.src = src
- image.onload = () => {
- setImage(image)
- imageCaches[src] = image
- }
- }, [src])
-
- // eslint-disable-next-line jsx-a11y/alt-text
- return <Image image={image} x={x} y={y} width={width} height={height} opacity={opacity} />
-}
-
-ImageComponent.propTypes = {
- src: PropTypes.string.isRequired,
- x: PropTypes.number.isRequired,
- y: PropTypes.number.isRequired,
- width: PropTypes.number.isRequired,
- height: PropTypes.number.isRequired,
- opacity: PropTypes.number.isRequired,
-}
-
-export default ImageComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/RackFillBar.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/RackFillBar.js
deleted file mode 100644
index aa284944..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/RackFillBar.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Group, Rect } from 'react-konva'
-import {
- RACK_ENERGY_BAR_BACKGROUND_COLOR,
- RACK_ENERGY_BAR_FILL_COLOR,
- RACK_SPACE_BAR_BACKGROUND_COLOR,
- RACK_SPACE_BAR_FILL_COLOR,
-} from '../../../../util/colors'
-import {
- OBJECT_BORDER_WIDTH_IN_PIXELS,
- OBJECT_MARGIN_IN_PIXELS,
- RACK_FILL_ICON_OPACITY,
- RACK_FILL_ICON_WIDTH,
- TILE_SIZE_IN_PIXELS,
-} from '../MapConstants'
-import ImageComponent from './ImageComponent'
-
-function RackFillBar({ positionX, positionY, type, fillFraction }) {
- const halfOfObjectBorderWidth = OBJECT_BORDER_WIDTH_IN_PIXELS / 2
- const x =
- positionX * TILE_SIZE_IN_PIXELS +
- OBJECT_MARGIN_IN_PIXELS +
- (type === 'space' ? halfOfObjectBorderWidth : 0.5 * (TILE_SIZE_IN_PIXELS - 2 * OBJECT_MARGIN_IN_PIXELS))
- const startY = positionY * TILE_SIZE_IN_PIXELS + OBJECT_MARGIN_IN_PIXELS + halfOfObjectBorderWidth
- const width = 0.5 * (TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS * 2) - halfOfObjectBorderWidth
- const fullHeight = TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS * 2 - OBJECT_BORDER_WIDTH_IN_PIXELS
-
- const fractionHeight = fillFraction * fullHeight
- const fractionY =
- (positionY + 1) * TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS - halfOfObjectBorderWidth - fractionHeight
-
- return (
- <Group>
- <Rect
- x={x}
- y={startY}
- width={width}
- height={fullHeight}
- fill={type === 'space' ? RACK_SPACE_BAR_BACKGROUND_COLOR : RACK_ENERGY_BAR_BACKGROUND_COLOR}
- />
- <Rect
- x={x}
- y={fractionY}
- width={width}
- height={fractionHeight}
- fill={type === 'space' ? RACK_SPACE_BAR_FILL_COLOR : RACK_ENERGY_BAR_FILL_COLOR}
- />
- <ImageComponent
- src={'/img/topology/rack-' + type + '-icon.png'}
- x={x + width * 0.5 - RACK_FILL_ICON_WIDTH * 0.5}
- y={startY + fullHeight * 0.5 - RACK_FILL_ICON_WIDTH * 0.5}
- width={RACK_FILL_ICON_WIDTH}
- height={RACK_FILL_ICON_WIDTH}
- opacity={RACK_FILL_ICON_OPACITY}
- />
- </Group>
- )
-}
-
-RackFillBar.propTypes = {
- positionX: PropTypes.number.isRequired,
- positionY: PropTypes.number.isRequired,
- type: PropTypes.string.isRequired,
- fillFraction: PropTypes.number.isRequired,
-}
-
-export default RackFillBar
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/RoomTile.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/RoomTile.js
deleted file mode 100644
index e7329dc0..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/RoomTile.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Rect } from 'react-konva'
-import { Tile } from '../../../../shapes'
-import { TILE_SIZE_IN_PIXELS } from '../MapConstants'
-
-function RoomTile({ tile, color }) {
- return (
- <Rect
- x={tile.positionX * TILE_SIZE_IN_PIXELS}
- y={tile.positionY * TILE_SIZE_IN_PIXELS}
- width={TILE_SIZE_IN_PIXELS}
- height={TILE_SIZE_IN_PIXELS}
- fill={color}
- />
- )
-}
-
-RoomTile.propTypes = {
- tile: Tile,
- color: PropTypes.string,
-}
-
-export default RoomTile
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/TileObject.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/TileObject.js
deleted file mode 100644
index 3211f187..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/TileObject.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Rect } from 'react-konva'
-import { OBJECT_BORDER_COLOR } from '../../../../util/colors'
-import { OBJECT_BORDER_WIDTH_IN_PIXELS, OBJECT_MARGIN_IN_PIXELS, TILE_SIZE_IN_PIXELS } from '../MapConstants'
-
-function TileObject({ positionX, positionY, color }) {
- return (
- <Rect
- x={positionX * TILE_SIZE_IN_PIXELS + OBJECT_MARGIN_IN_PIXELS}
- y={positionY * TILE_SIZE_IN_PIXELS + OBJECT_MARGIN_IN_PIXELS}
- width={TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS * 2}
- height={TILE_SIZE_IN_PIXELS - OBJECT_MARGIN_IN_PIXELS * 2}
- fill={color}
- stroke={OBJECT_BORDER_COLOR}
- strokeWidth={OBJECT_BORDER_WIDTH_IN_PIXELS}
- />
- )
-}
-
-TileObject.propTypes = {
- positionX: PropTypes.number.isRequired,
- positionY: PropTypes.number.isRequired,
- color: PropTypes.string.isRequired,
-}
-
-export default TileObject
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/TilePlusIcon.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/TilePlusIcon.js
deleted file mode 100644
index 186c2b3a..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/TilePlusIcon.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Group, Line } from 'react-konva'
-import { TILE_PLUS_COLOR } from '../../../../util/colors'
-import { TILE_PLUS_MARGIN_IN_PIXELS, TILE_PLUS_WIDTH_IN_PIXELS, TILE_SIZE_IN_PIXELS } from '../MapConstants'
-
-function TilePlusIcon({ x, y, scale = 1 }) {
- const linePoints = [
- [
- x + 0.5 * TILE_SIZE_IN_PIXELS * scale,
- y + TILE_PLUS_MARGIN_IN_PIXELS * scale,
- x + 0.5 * TILE_SIZE_IN_PIXELS * scale,
- y + TILE_SIZE_IN_PIXELS * scale - TILE_PLUS_MARGIN_IN_PIXELS * scale,
- ],
- [
- x + TILE_PLUS_MARGIN_IN_PIXELS * scale,
- y + 0.5 * TILE_SIZE_IN_PIXELS * scale,
- x + TILE_SIZE_IN_PIXELS * scale - TILE_PLUS_MARGIN_IN_PIXELS * scale,
- y + 0.5 * TILE_SIZE_IN_PIXELS * scale,
- ],
- ]
- return (
- <Group>
- {linePoints.map((points, index) => (
- <Line
- key={index}
- points={points}
- lineCap="round"
- stroke={TILE_PLUS_COLOR}
- strokeWidth={TILE_PLUS_WIDTH_IN_PIXELS * scale}
- listening={false}
- />
- ))}
- </Group>
- )
-}
-
-TilePlusIcon.propTypes = {
- x: PropTypes.number,
- y: PropTypes.number,
- scale: PropTypes.number,
-}
-
-export default TilePlusIcon
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/WallSegment.js b/opendc-web/opendc-web-ui/src/components/topologies/map/elements/WallSegment.js
deleted file mode 100644
index 4f18813e..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/elements/WallSegment.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import React from 'react'
-import { Line } from 'react-konva'
-import { WallSegment as WallSegmentShape } from '../../../../shapes'
-import { WALL_COLOR } from '../../../../util/colors'
-import { TILE_SIZE_IN_PIXELS, WALL_WIDTH_IN_PIXELS } from '../MapConstants'
-
-function WallSegment({ wallSegment }) {
- let points
- if (wallSegment.isHorizontal) {
- points = [
- wallSegment.startPosX * TILE_SIZE_IN_PIXELS,
- wallSegment.startPosY * TILE_SIZE_IN_PIXELS,
- (wallSegment.startPosX + wallSegment.length) * TILE_SIZE_IN_PIXELS,
- wallSegment.startPosY * TILE_SIZE_IN_PIXELS,
- ]
- } else {
- points = [
- wallSegment.startPosX * TILE_SIZE_IN_PIXELS,
- wallSegment.startPosY * TILE_SIZE_IN_PIXELS,
- wallSegment.startPosX * TILE_SIZE_IN_PIXELS,
- (wallSegment.startPosY + wallSegment.length) * TILE_SIZE_IN_PIXELS,
- ]
- }
-
- return <Line points={points} lineCap="round" stroke={WALL_COLOR} strokeWidth={WALL_WIDTH_IN_PIXELS} />
-}
-
-WallSegment.propTypes = {
- wallSegment: WallSegmentShape,
-}
-
-export default WallSegment
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/GridGroup.js b/opendc-web/opendc-web-ui/src/components/topologies/map/groups/GridGroup.js
deleted file mode 100644
index d66a18de..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/GridGroup.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react'
-import { Group, Line } from 'react-konva'
-import { GRID_COLOR } from '../../../../util/colors'
-import { GRID_LINE_WIDTH_IN_PIXELS, MAP_SIZE, MAP_SIZE_IN_PIXELS, TILE_SIZE_IN_PIXELS } from '../MapConstants'
-
-const MAP_COORDINATE_ENTRIES = Array.from(new Array(MAP_SIZE), (x, i) => i)
-const HORIZONTAL_POINT_PAIRS = MAP_COORDINATE_ENTRIES.map((index) => [
- 0,
- index * TILE_SIZE_IN_PIXELS,
- MAP_SIZE_IN_PIXELS,
- index * TILE_SIZE_IN_PIXELS,
-])
-const VERTICAL_POINT_PAIRS = MAP_COORDINATE_ENTRIES.map((index) => [
- index * TILE_SIZE_IN_PIXELS,
- 0,
- index * TILE_SIZE_IN_PIXELS,
- MAP_SIZE_IN_PIXELS,
-])
-
-function GridGroup() {
- return (
- <Group>
- {HORIZONTAL_POINT_PAIRS.concat(VERTICAL_POINT_PAIRS).map((points, index) => (
- <Line
- key={index}
- points={points}
- stroke={GRID_COLOR}
- strokeWidth={GRID_LINE_WIDTH_IN_PIXELS}
- listening={false}
- />
- ))}
- </Group>
- )
-}
-
-export default GridGroup
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/RackGroup.js b/opendc-web/opendc-web-ui/src/components/topologies/map/groups/RackGroup.js
deleted file mode 100644
index ed942661..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/RackGroup.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import React from 'react'
-import { Group } from 'react-konva'
-import { Tile } from '../../../../shapes'
-import { RACK_BACKGROUND_COLOR } from '../../../../util/colors'
-import TileObject from '../elements/TileObject'
-import RackSpaceFillContainer from '../RackSpaceFillContainer'
-import RackEnergyFillContainer from '../RackEnergyFillContainer'
-
-function RackGroup({ tile }) {
- return (
- <Group>
- <TileObject positionX={tile.positionX} positionY={tile.positionY} color={RACK_BACKGROUND_COLOR} />
- <Group>
- <RackSpaceFillContainer rackId={tile.rack} positionX={tile.positionX} positionY={tile.positionY} />
- <RackEnergyFillContainer rackId={tile.rack} positionX={tile.positionX} positionY={tile.positionY} />
- </Group>
- </Group>
- )
-}
-
-RackGroup.propTypes = {
- tile: Tile,
-}
-
-export default RackGroup
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/RoomGroup.js b/opendc-web/opendc-web-ui/src/components/topologies/map/groups/RoomGroup.js
deleted file mode 100644
index 3f8b3089..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/RoomGroup.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Group } from 'react-konva'
-import { InteractionLevel, Room } from '../../../../shapes'
-import GrayContainer from '../GrayContainer'
-import TileContainer from '../TileContainer'
-import WallContainer from '../WallContainer'
-
-function RoomGroup({ room, interactionLevel, currentRoomInConstruction, onClick }) {
- if (currentRoomInConstruction === room.id) {
- return (
- <Group onClick={onClick}>
- {room.tiles.map((tileId) => (
- <TileContainer key={tileId} tileId={tileId} newTile={true} />
- ))}
- </Group>
- )
- }
-
- return (
- <Group onClick={onClick}>
- {(() => {
- if (
- (interactionLevel.mode === 'RACK' || interactionLevel.mode === 'MACHINE') &&
- interactionLevel.roomId === room.id
- ) {
- return [
- room.tiles
- .filter((tileId) => tileId !== interactionLevel.tileId)
- .map((tileId) => <TileContainer key={tileId} tileId={tileId} />),
- <GrayContainer key={-1} />,
- room.tiles
- .filter((tileId) => tileId === interactionLevel.tileId)
- .map((tileId) => <TileContainer key={tileId} tileId={tileId} />),
- ]
- } else {
- return room.tiles.map((tileId) => <TileContainer key={tileId} tileId={tileId} />)
- }
- })()}
- <WallContainer roomId={room.id} />
- </Group>
- )
-}
-
-RoomGroup.propTypes = {
- room: Room,
- interactionLevel: InteractionLevel,
- currentRoomInConstruction: PropTypes.string,
- onClick: PropTypes.func,
-}
-
-export default RoomGroup
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/TileGroup.js b/opendc-web/opendc-web-ui/src/components/topologies/map/groups/TileGroup.js
deleted file mode 100644
index f2084017..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/TileGroup.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Group } from 'react-konva'
-import { Tile } from '../../../../shapes'
-import { ROOM_DEFAULT_COLOR, ROOM_IN_CONSTRUCTION_COLOR } from '../../../../util/colors'
-import RoomTile from '../elements/RoomTile'
-import RackContainer from '../RackContainer'
-
-function TileGroup({ tile, newTile, onClick }) {
- let tileObject
- if (tile.rack) {
- tileObject = <RackContainer tile={tile} />
- } else {
- tileObject = null
- }
-
- let color = ROOM_DEFAULT_COLOR
- if (newTile) {
- color = ROOM_IN_CONSTRUCTION_COLOR
- }
-
- return (
- <Group onClick={() => onClick(tile)}>
- <RoomTile tile={tile} color={color} />
- {tileObject}
- </Group>
- )
-}
-
-TileGroup.propTypes = {
- tile: Tile,
- newTile: PropTypes.bool,
- onClick: PropTypes.func,
-}
-
-export default TileGroup
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/TopologyGroup.js b/opendc-web/opendc-web-ui/src/components/topologies/map/groups/TopologyGroup.js
deleted file mode 100644
index 011dcf34..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/TopologyGroup.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import React from 'react'
-import { Group } from 'react-konva'
-import { InteractionLevel, Topology } from '../../../../shapes'
-import RoomContainer from '../RoomContainer'
-import GrayContainer from '../GrayContainer'
-
-function TopologyGroup({ topology, interactionLevel }) {
- if (!topology) {
- return <Group />
- }
-
- if (interactionLevel.mode === 'BUILDING') {
- return (
- <Group>
- {topology.rooms.map((roomId) => (
- <RoomContainer key={roomId} roomId={roomId} />
- ))}
- </Group>
- )
- }
-
- return (
- <Group>
- {topology.rooms
- .filter((roomId) => roomId !== interactionLevel.roomId)
- .map((roomId) => (
- <RoomContainer key={roomId} roomId={roomId} />
- ))}
- {interactionLevel.mode === 'ROOM' ? <GrayContainer /> : null}
- {topology.rooms
- .filter((roomId) => roomId === interactionLevel.roomId)
- .map((roomId) => (
- <RoomContainer key={roomId} roomId={roomId} />
- ))}
- </Group>
- )
-}
-
-TopologyGroup.propTypes = {
- topology: Topology,
- interactionLevel: InteractionLevel,
-}
-
-export default TopologyGroup
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/WallGroup.js b/opendc-web/opendc-web-ui/src/components/topologies/map/groups/WallGroup.js
deleted file mode 100644
index 6cbd1cd0..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/groups/WallGroup.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Group } from 'react-konva'
-import { Tile } from '../../../../shapes'
-import { deriveWallLocations } from '../../../../util/tile-calculations'
-import WallSegment from '../elements/WallSegment'
-
-function WallGroup({ tiles }) {
- return (
- <Group>
- {deriveWallLocations(tiles).map((wallSegment, index) => (
- <WallSegment key={index} wallSegment={wallSegment} />
- ))}
- </Group>
- )
-}
-
-WallGroup.propTypes = {
- tiles: PropTypes.arrayOf(Tile).isRequired,
-}
-
-export default WallGroup
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js
deleted file mode 100644
index d7e0c56a..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/HoverLayerComponent.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useMemo, useState } from 'react'
-import { Layer } from 'react-konva/lib/ReactKonva'
-import HoverTile from '../elements/HoverTile'
-import { TILE_SIZE_IN_PIXELS } from '../MapConstants'
-import { useEffectRef } from '../../../../util/effect-ref'
-
-function HoverLayerComponent({ isEnabled, isValid, onClick, children }) {
- const [[mouseWorldX, mouseWorldY], setPos] = useState([0, 0])
-
- const layerRef = useEffectRef((layer) => {
- if (!layer) {
- return
- }
-
- const stage = layer.getStage()
-
- stage.on('mousemove.hover', () => {
- // Transform used to convert mouse coordinates to world coordinates
- const transform = stage.getAbsoluteTransform().copy()
- transform.invert()
-
- const { x, y } = transform.point(stage.getPointerPosition())
- setPos([x, y])
- })
- return () => stage.off('mousemove.hover')
- })
-
- const gridX = Math.floor(mouseWorldX / TILE_SIZE_IN_PIXELS)
- const gridY = Math.floor(mouseWorldY / TILE_SIZE_IN_PIXELS)
- const valid = useMemo(() => isEnabled && isValid(gridX, gridY), [isEnabled, isValid, gridX, gridY])
-
- if (!isEnabled) {
- return <Layer />
- }
-
- const x = gridX * TILE_SIZE_IN_PIXELS
- const y = gridY * TILE_SIZE_IN_PIXELS
-
- return (
- <Layer opacity={0.2} ref={layerRef}>
- <HoverTile x={x} y={y} isValid={valid} onClick={() => (valid ? onClick(gridX, gridY) : undefined)} />
- {children ? React.cloneElement(children, { x, y, scale: 1 }) : undefined}
- </Layer>
- )
-}
-
-HoverLayerComponent.propTypes = {
- isEnabled: PropTypes.bool.isRequired,
- isValid: PropTypes.func.isRequired,
- onClick: PropTypes.func.isRequired,
- children: PropTypes.node,
-}
-
-export default HoverLayerComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js
deleted file mode 100644
index c902532b..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/MapLayer.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { Group, Layer } from 'react-konva'
-import Backdrop from '../elements/Backdrop'
-import TopologyContainer from '../TopologyContainer'
-import GridGroup from '../groups/GridGroup'
-
-function MapLayer() {
- return (
- <Layer>
- <Group>
- <Backdrop />
- <TopologyContainer />
- <GridGroup />
- </Group>
- </Layer>
- )
-}
-
-export default MapLayer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js
deleted file mode 100644
index 5e741a3b..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/ObjectHoverLayer.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { addRackToTile } from '../../../../redux/actions/topology/room'
-import { findTileWithPosition } from '../../../../util/tile-calculations'
-import HoverLayerComponent from './HoverLayerComponent'
-import TilePlusIcon from '../elements/TilePlusIcon'
-
-export default function ObjectHoverLayer() {
- const isEnabled = useSelector((state) => state.construction.inRackConstructionMode)
- const isValid = useSelector((state) => (x, y) => {
- if (state.interactionLevel.mode !== 'ROOM') {
- return false
- }
-
- const currentRoom = state.topology.rooms[state.interactionLevel.roomId]
- const tiles = currentRoom.tiles.map((tileId) => state.topology.tiles[tileId])
- const tile = findTileWithPosition(tiles, x, y)
-
- return !(tile === null || tile.rack)
- })
-
- const dispatch = useDispatch()
- const onClick = (x, y) => dispatch(addRackToTile(x, y))
- return (
- <HoverLayerComponent onClick={onClick} isEnabled={isEnabled} isValid={isValid}>
- <TilePlusIcon />
- </HoverLayerComponent>
- )
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js b/opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js
deleted file mode 100644
index b9cfcaf4..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/map/layers/RoomHoverLayer.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { toggleTileAtLocation } from '../../../../redux/actions/topology/building'
-import {
- deriveValidNextTilePositions,
- findPositionInPositions,
- findPositionInRooms,
-} from '../../../../util/tile-calculations'
-import HoverLayerComponent from './HoverLayerComponent'
-
-export default function RoomHoverLayer() {
- const dispatch = useDispatch()
- const onClick = (x, y) => dispatch(toggleTileAtLocation(x, y))
- const isEnabled = useSelector((state) => state.construction.currentRoomInConstruction !== '-1')
- const isValid = useSelector((state) => (x, y) => {
- const newRoom = { ...state.topology.rooms[state.construction.currentRoomInConstruction] }
- const oldRooms = Object.keys(state.topology.rooms)
- .map((id) => ({ ...state.topology.rooms[id] }))
- .filter(
- (room) =>
- state.topology.root.rooms.indexOf(room.id) !== -1 &&
- room.id !== state.construction.currentRoomInConstruction
- )
-
- ;[...oldRooms, newRoom].forEach((room) => {
- room.tiles = room.tiles.map((tileId) => state.topology.tiles[tileId])
- })
- if (newRoom.tiles.length === 0) {
- return findPositionInRooms(oldRooms, x, y) === -1
- }
-
- const validNextPositions = deriveValidNextTilePositions(oldRooms, newRoom.tiles)
- return findPositionInPositions(validNextPositions, x, y) !== -1
- })
-
- return <HoverLayerComponent onClick={onClick} isEnabled={isEnabled} isValid={isValid} />
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/NameComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/NameComponent.js
deleted file mode 100644
index ececd07b..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/NameComponent.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useRef, useState } from 'react'
-import { Button, TextInput } from '@patternfly/react-core'
-import { PencilAltIcon, CheckIcon, TimesIcon } from '@patternfly/react-icons'
-
-function NameComponent({ name, onEdit }) {
- const [isEditing, setEditing] = useState(false)
- const nameInput = useRef(null)
-
- const onCancel = () => {
- nameInput.current.value = name
- setEditing(false)
- }
-
- const onSubmit = (event) => {
- if (event) {
- event.preventDefault()
- }
-
- const name = nameInput.current.value
- if (name) {
- onEdit(name)
- }
-
- setEditing(false)
- }
-
- return (
- <form
- className={`pf-c-inline-edit ${isEditing ? 'pf-m-inline-editable' : ''} pf-u-display-inline-block`}
- onSubmit={onSubmit}
- >
- <div className="pf-c-inline-edit__group">
- <div className="pf-c-inline-edit__value" id="single-inline-edit-example-label">
- {name}
- </div>
- <div className="pf-c-inline-edit__action pf-m-enable-editable">
- <Button className="pf-u-py-0" variant="plain" aria-label="Edit" onClick={() => setEditing(true)}>
- <PencilAltIcon />
- </Button>
- </div>
- </div>
- <div className="pf-c-inline-edit__group">
- <div className="pf-c-inline-edit__input">
- <TextInput type="text" defaultValue={name} ref={nameInput} aria-label="Editable text input" />
- </div>
- <div className="pf-c-inline-edit__group pf-m-action-group pf-m-icon-group">
- <div className="pf-c-inline-edit__action pf-m-valid">
- <Button className="pf-u-py-0" variant="plain" aria-label="Save edits" onClick={onSubmit}>
- <CheckIcon />
- </Button>
- </div>
- <div className="pf-c-inline-edit__action">
- <Button className="pf-u-py-0" variant="plain" aria-label="Cancel edits" onClick={onCancel}>
- <TimesIcon />
- </Button>
- </div>
- </div>
- </div>
- </form>
- )
-}
-
-NameComponent.propTypes = {
- name: PropTypes.string,
- onEdit: PropTypes.func,
-}
-
-export default NameComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.js
deleted file mode 100644
index 5aaa7834..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.js
+++ /dev/null
@@ -1,83 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { InteractionLevel } from '../../../shapes'
-import BuildingSidebar from './building/BuildingSidebar'
-import {
- Button,
- DrawerActions,
- DrawerCloseButton,
- DrawerHead,
- DrawerPanelBody,
- DrawerPanelContent,
- Flex,
- Title,
-} from '@patternfly/react-core'
-import { AngleLeftIcon } from '@patternfly/react-icons'
-import { useDispatch } from 'react-redux'
-import { backButton } from './TopologySidebar.module.css'
-import RoomSidebar from './room/RoomSidebar'
-import RackSidebar from './rack/RackSidebar'
-import MachineSidebar from './machine/MachineSidebar'
-import { goDownOneInteractionLevel } from '../../../redux/actions/interaction-level'
-
-const name = {
- BUILDING: 'Building',
- ROOM: 'Room',
- RACK: 'Rack',
- MACHINE: 'Machine',
-}
-
-function TopologySidebar({ interactionLevel, onClose }) {
- let sidebarContent
-
- switch (interactionLevel.mode) {
- case 'BUILDING':
- sidebarContent = <BuildingSidebar />
- break
- case 'ROOM':
- sidebarContent = <RoomSidebar roomId={interactionLevel.roomId} />
- break
- case 'RACK':
- sidebarContent = <RackSidebar tileId={interactionLevel.tileId} />
- break
- case 'MACHINE':
- sidebarContent = <MachineSidebar tileId={interactionLevel.tileId} position={interactionLevel.position} />
- break
- default:
- sidebarContent = 'Missing Content'
- }
-
- const dispatch = useDispatch()
- const onClick = () => dispatch(goDownOneInteractionLevel())
-
- return (
- <DrawerPanelContent isResizable defaultSize="450px" minSize="400px">
- <DrawerHead>
- <Flex>
- <Button
- variant="tertiary"
- isSmall
- className={backButton}
- onClick={interactionLevel.mode === 'BUILDING' ? onClose : onClick}
- >
- <AngleLeftIcon />
- </Button>
- <Title className="pf-u-align-self-center" headingLevel="h1">
- {name[interactionLevel.mode]}
- </Title>
- </Flex>
- <DrawerActions>
- <DrawerCloseButton onClose={onClose} />
- </DrawerActions>
- </DrawerHead>
- <DrawerPanelBody>{sidebarContent}</DrawerPanelBody>
- </DrawerPanelContent>
- )
-}
-
-TopologySidebar.propTypes = {
- interactionLevel: InteractionLevel,
- onClose: PropTypes.func,
-}
-
-export default TopologySidebar
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.module.css b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.module.css
deleted file mode 100644
index 3853c625..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/TopologySidebar.module.css
+++ /dev/null
@@ -1,35 +0,0 @@
-/*!
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-.backButton:global(.pf-c-button) {
- align-self: center;
- --pf-c-button--after--BorderColor: var(--pf-global--BorderColor--light-100);
- color: var(--pf-global--Color--400);
-
- --pf-c-button--PaddingRight: var(--pf-global--spacer--sm);
- --pf-c-button--PaddingLeft: var(--pf-global--spacer--sm);
-}
-
-.backButton:hover,
-.backButton:global(.pf-c-button):focus {
- --pf-c-button--after--BorderColor: var(--pf-global--BorderColor--100);
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/BuildingSidebar.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/BuildingSidebar.js
deleted file mode 100644
index 5fcd46be..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/BuildingSidebar.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from 'react'
-import NewRoomConstructionContainer from './NewRoomConstructionContainer'
-
-function BuildingSidebar() {
- return <NewRoomConstructionContainer />
-}
-
-export default BuildingSidebar
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionComponent.js
deleted file mode 100644
index 9fc85d0c..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionComponent.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Button, Toolbar, ToolbarContent, ToolbarGroup, ToolbarItem } from '@patternfly/react-core'
-import PlusIcon from '@patternfly/react-icons/dist/js/icons/plus-icon'
-import CheckIcon from '@patternfly/react-icons/dist/js/icons/check-icon'
-
-function NewRoomConstructionComponent({ onStart, onFinish, onCancel, currentRoomInConstruction }) {
- if (currentRoomInConstruction === '-1') {
- return (
- <Button isBlock icon={<PlusIcon />} onClick={onStart}>
- Construct a new room
- </Button>
- )
- }
- return (
- <Toolbar
- inset={{
- default: 'insetNone',
- }}
- >
- <ToolbarContent>
- <ToolbarGroup>
- <ToolbarItem>
- <Button icon={<CheckIcon />} onClick={onFinish}>
- Finalize new room
- </Button>
- </ToolbarItem>
- <ToolbarItem widths={{ default: '100%' }}>
- <Button isBlock variant="secondary" onClick={onCancel}>
- Cancel
- </Button>
- </ToolbarItem>
- </ToolbarGroup>
- </ToolbarContent>
- </Toolbar>
- )
-}
-
-NewRoomConstructionComponent.propTypes = {
- onStart: PropTypes.func,
- onFinish: PropTypes.func,
- onCancel: PropTypes.func,
- currentRoomInConstruction: PropTypes.string,
-}
-
-export default NewRoomConstructionComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionContainer.js
deleted file mode 100644
index c149b224..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/building/NewRoomConstructionContainer.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import {
- cancelNewRoomConstruction,
- finishNewRoomConstruction,
- startNewRoomConstruction,
-} from '../../../../redux/actions/topology/building'
-import NewRoomConstructionComponent from './NewRoomConstructionComponent'
-
-function NewRoomConstructionButton() {
- const currentRoomInConstruction = useSelector((state) => state.construction.currentRoomInConstruction)
- const dispatch = useDispatch()
-
- return (
- <NewRoomConstructionComponent
- onStart={() => dispatch(startNewRoomConstruction())}
- onFinish={() => dispatch(finishNewRoomConstruction())}
- onCancel={() => dispatch(cancelNewRoomConstruction())}
- currentRoomInConstruction={currentRoomInConstruction}
- />
- )
-}
-
-export default NewRoomConstructionButton
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/DeleteMachine.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/DeleteMachine.js
deleted file mode 100644
index a4b9457b..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/DeleteMachine.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React, { useState } from 'react'
-import { useDispatch } from 'react-redux'
-import { Button } from '@patternfly/react-core'
-import { TrashIcon } from '@patternfly/react-icons'
-import ConfirmationModal from '../../../util/modals/ConfirmationModal'
-import { deleteMachine } from '../../../../redux/actions/topology/machine'
-
-function DeleteMachine({ machineId }) {
- const dispatch = useDispatch()
- const [isVisible, setVisible] = useState(false)
- const callback = (isConfirmed) => {
- if (isConfirmed) {
- dispatch(deleteMachine(machineId))
- }
- setVisible(false)
- }
- return (
- <>
- <Button variant="danger" icon={<TrashIcon />} isBlock onClick={() => setVisible(true)}>
- Delete this machine
- </Button>
- <ConfirmationModal
- title="Delete this machine"
- message="Are you sure you want to delete this machine?"
- isOpen={isVisible}
- callback={callback}
- />
- </>
- )
-}
-
-DeleteMachine.propTypes = {
- machineId: PropTypes.string.isRequired,
-}
-
-export default DeleteMachine
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/MachineSidebar.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/MachineSidebar.js
deleted file mode 100644
index 8a4c33dc..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/MachineSidebar.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import UnitTabsComponent from './UnitTabsComponent'
-import DeleteMachine from './DeleteMachine'
-import {
- TextContent,
- TextList,
- TextListItem,
- TextListItemVariants,
- TextListVariants,
- Title,
-} from '@patternfly/react-core'
-import { useSelector } from 'react-redux'
-
-function MachineSidebar({ tileId, position }) {
- const machine = useSelector(({ topology }) => {
- const rack = topology.racks[topology.tiles[tileId].rack]
-
- for (const machineId of rack.machines) {
- const machine = topology.machines[machineId]
- if (machine.position === position) {
- return machine
- }
- }
- })
- const machineId = machine.id
- return (
- <div>
- <TextContent>
- <Title headingLevel="h2">Details</Title>
- <TextList component={TextListVariants.dl}>
- <TextListItem component={TextListItemVariants.dt}>Name</TextListItem>
- <TextListItem component={TextListItemVariants.dd}>
- Machine at position {machine.position}
- </TextListItem>
- </TextList>
-
- <Title headingLevel="h2">Actions</Title>
- <DeleteMachine machineId={machineId} />
-
- <Title headingLevel="h2">Units</Title>
- </TextContent>
- <div className="pf-u-h-100">
- <UnitTabsComponent machineId={machineId} />
- </div>
- </div>
- )
-}
-
-MachineSidebar.propTypes = {
- tileId: PropTypes.string.isRequired,
- position: PropTypes.number.isRequired,
-}
-
-export default MachineSidebar
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddComponent.js
deleted file mode 100644
index 18cba23a..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddComponent.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useState } from 'react'
-import { Button, InputGroup, Select, SelectOption, SelectVariant } from '@patternfly/react-core'
-import PlusIcon from '@patternfly/react-icons/dist/js/icons/plus-icon'
-
-function UnitAddComponent({ units, onAdd }) {
- const [isOpen, setOpen] = useState(false)
- const [selected, setSelected] = useState(null)
-
- return (
- <InputGroup>
- <Select
- variant={SelectVariant.single}
- placeholderText="Select a unit"
- aria-label="Select Unit"
- onToggle={() => setOpen(!isOpen)}
- isOpen={isOpen}
- onSelect={(_, selection) => {
- setSelected(selection)
- setOpen(false)
- }}
- selections={selected}
- >
- {units.map((unit) => (
- <SelectOption value={unit.id} key={unit.id}>
- {unit.name}
- </SelectOption>
- ))}
- </Select>
- <Button icon={<PlusIcon />} variant="control" onClick={() => onAdd(selected)} isDisabled={!selected}>
- Add
- </Button>
- </InputGroup>
- )
-}
-
-UnitAddComponent.propTypes = {
- units: PropTypes.array.isRequired,
- onAdd: PropTypes.func.isRequired,
-}
-
-export default UnitAddComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js
deleted file mode 100644
index a0054ef6..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitAddContainer.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import UnitAddComponent from './UnitAddComponent'
-import { addUnit } from '../../../../redux/actions/topology/machine'
-import UnitType from './UnitType'
-
-function UnitAddContainer({ machineId, unitType }) {
- const units = useSelector((state) => Object.values(state.topology[unitType]))
- const dispatch = useDispatch()
-
- const onAdd = (id) => dispatch(addUnit(machineId, unitType, id))
-
- return <UnitAddComponent onAdd={onAdd} units={units} />
-}
-
-UnitAddContainer.propTypes = {
- machineId: PropTypes.string.isRequired,
- unitType: UnitType.isRequired,
-}
-
-export default UnitAddContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js
deleted file mode 100644
index 75ab0ad7..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListComponent.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import {
- Button,
- DataList,
- DataListAction,
- DataListCell,
- DataListItem,
- DataListItemCells,
- DataListItemRow,
- DescriptionList,
- DescriptionListDescription,
- DescriptionListGroup,
- DescriptionListTerm,
- EmptyState,
- EmptyStateBody,
- EmptyStateIcon,
- Popover,
- Title,
-} from '@patternfly/react-core'
-import { CubesIcon, InfoIcon, TrashIcon } from '@patternfly/react-icons'
-import { ProcessingUnit, StorageUnit } from '../../../../shapes'
-import UnitType from './UnitType'
-
-function UnitInfo({ unit, unitType }) {
- if (unitType === 'cpus' || unitType === 'gpus') {
- return (
- <DescriptionList>
- <DescriptionListGroup>
- <DescriptionListTerm>Clock Frequency</DescriptionListTerm>
- <DescriptionListDescription>{unit.clockRateMhz} MHz</DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Number of Cores</DescriptionListTerm>
- <DescriptionListDescription>{unit.numberOfCores}</DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Energy Consumption</DescriptionListTerm>
- <DescriptionListDescription>{unit.energyConsumptionW} W</DescriptionListDescription>
- </DescriptionListGroup>
- </DescriptionList>
- )
- }
-
- return (
- <DescriptionList>
- <DescriptionListGroup>
- <DescriptionListTerm>Speed</DescriptionListTerm>
- <DescriptionListDescription>{unit.speedMbPerS} Mb/s</DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Capacity</DescriptionListTerm>
- <DescriptionListDescription>{unit.sizeMb} MB</DescriptionListDescription>
- </DescriptionListGroup>
- <DescriptionListGroup>
- <DescriptionListTerm>Energy Consumption</DescriptionListTerm>
- <DescriptionListDescription>{unit.energyConsumptionW} W</DescriptionListDescription>
- </DescriptionListGroup>
- </DescriptionList>
- )
-}
-
-UnitInfo.propTypes = {
- unitType: UnitType.isRequired,
- unit: PropTypes.oneOfType([ProcessingUnit, StorageUnit]).isRequired,
-}
-
-function UnitListComponent({ unitType, units, onDelete }) {
- if (units.length === 0) {
- return (
- <EmptyState>
- <EmptyStateIcon icon={CubesIcon} />
- <Title headingLevel="h5" size="lg">
- No units found
- </Title>
- <EmptyStateBody>You have not configured any units yet. Add some with the menu above!</EmptyStateBody>
- </EmptyState>
- )
- }
-
- return (
- <DataList aria-label="Machine Units" isCompact>
- {units.map((unit, index) => (
- <DataListItem key={index}>
- <DataListItemRow>
- <DataListItemCells dataListCells={[<DataListCell key="unit">{unit.name}</DataListCell>]} />
- <DataListAction id="goto" aria-label="Goto Machine" aria-labelledby="goto">
- <Popover
- headerContent="Unit Information"
- bodyContent={<UnitInfo unitType={unitType} unit={unit} />}
- >
- <Button isSmall variant="plain" className="pf-u-p-0">
- <InfoIcon />
- </Button>
- </Popover>
- <Button isSmall variant="plain" className="pf-u-p-0" onClick={() => onDelete(units[index])}>
- <TrashIcon />
- </Button>
- </DataListAction>
- </DataListItemRow>
- </DataListItem>
- ))}
- </DataList>
- )
-}
-
-UnitListComponent.propTypes = {
- unitType: UnitType.isRequired,
- units: PropTypes.arrayOf(PropTypes.oneOfType([ProcessingUnit, StorageUnit])).isRequired,
- onDelete: PropTypes.func,
-}
-
-export default UnitListComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js
deleted file mode 100644
index bcd4bdcc..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitListContainer.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import UnitListComponent from './UnitListComponent'
-import { deleteUnit } from '../../../../redux/actions/topology/machine'
-import UnitType from './UnitType'
-
-function UnitListContainer({ machineId, unitType }) {
- const dispatch = useDispatch()
- const units = useSelector((state) => {
- const machine = state.topology.machines[machineId]
- return machine[unitType].map((id) => state.topology[unitType][id])
- })
-
- const onDelete = (unit) => dispatch(deleteUnit(machineId, unitType, unit.id))
-
- return <UnitListComponent units={units} unitType={unitType} onDelete={onDelete} />
-}
-
-UnitListContainer.propTypes = {
- machineId: PropTypes.string.isRequired,
- unitType: UnitType.isRequired,
-}
-
-export default UnitListContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitTabsComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitTabsComponent.js
deleted file mode 100644
index 4032d607..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitTabsComponent.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useState } from 'react'
-import { Tab, Tabs, TabTitleText } from '@patternfly/react-core'
-import UnitAddContainer from './UnitAddContainer'
-import UnitListContainer from './UnitListContainer'
-
-function UnitTabsComponent({ machineId }) {
- const [activeTab, setActiveTab] = useState('cpuModel-units')
-
- return (
- <Tabs activeKey={activeTab} onSelect={(_, tab) => setActiveTab(tab)}>
- <Tab eventKey="cpuModel-units" title={<TabTitleText>CPU</TabTitleText>}>
- <UnitAddContainer machineId={machineId} unitType="cpus" />
- <UnitListContainer machineId={machineId} unitType="cpus" />
- </Tab>
- <Tab eventKey="gpu-units" title={<TabTitleText>GPU</TabTitleText>}>
- <UnitAddContainer machineId={machineId} unitType="gpus" />
- <UnitListContainer machineId={machineId} unitType="gpus" />
- </Tab>
- <Tab eventKey="memory-units" title={<TabTitleText>Memory</TabTitleText>}>
- <UnitAddContainer machineId={machineId} unitType="memories" />
- <UnitListContainer machineId={machineId} unitType="memories" />
- </Tab>
- <Tab eventKey="storage-units" title={<TabTitleText>Storage</TabTitleText>}>
- <UnitAddContainer machineId={machineId} unitType="storages" />
- <UnitListContainer machineId={machineId} unitType="storages" />
- </Tab>
- </Tabs>
- )
-}
-
-UnitTabsComponent.propTypes = {
- machineId: PropTypes.string.isRequired,
-}
-
-export default UnitTabsComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js
deleted file mode 100644
index b6d7bf8b..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/machine/UnitType.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-
-export default PropTypes.oneOf(['cpus', 'gpus', 'memories', 'storages'])
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/AddPrefab.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/AddPrefab.js
deleted file mode 100644
index 6a0c3ff3..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/AddPrefab.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Button } from '@patternfly/react-core'
-import { SaveIcon } from '@patternfly/react-icons'
-
-function AddPrefab() {
- const onClick = () => {} // TODO
- return (
- <Button variant="primary" icon={<SaveIcon />} isBlock onClick={onClick} className="pf-u-mb-sm">
- Save this rack to a prefab
- </Button>
- )
-}
-
-AddPrefab.propTypes = {
- tileId: PropTypes.string.isRequired,
-}
-
-export default AddPrefab
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/DeleteRackContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/DeleteRackContainer.js
deleted file mode 100644
index 0583a7a4..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/DeleteRackContainer.js
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React, { useState } from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import TrashIcon from '@patternfly/react-icons/dist/js/icons/trash-icon'
-import { Button } from '@patternfly/react-core'
-import ConfirmationModal from '../../../util/modals/ConfirmationModal'
-import { deleteRack } from '../../../../redux/actions/topology/rack'
-
-function DeleteRackContainer({ tileId }) {
- const dispatch = useDispatch()
- const [isVisible, setVisible] = useState(false)
- const rackId = useSelector((state) => state.topology.tiles[tileId].rack)
- const callback = (isConfirmed) => {
- if (isConfirmed) {
- dispatch(deleteRack(tileId, rackId))
- }
- setVisible(false)
- }
- return (
- <>
- <Button variant="danger" icon={<TrashIcon />} isBlock onClick={() => setVisible(true)}>
- Delete this rack
- </Button>
- <ConfirmationModal
- title="Delete this rack"
- message="Are you sure you want to delete this rack?"
- isOpen={isVisible}
- callback={callback}
- />
- </>
- )
-}
-
-DeleteRackContainer.propTypes = {
- tileId: PropTypes.string.isRequired,
-}
-
-export default DeleteRackContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineComponent.js
deleted file mode 100644
index b0a96a9f..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineComponent.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Flex, Label } from '@patternfly/react-core'
-import { Machine } from '../../../../shapes'
-
-const UnitIcon = ({ id, type }) => (
- // eslint-disable-next-line @next/next/no-img-element
- <img src={'/img/topology/' + id + '-icon.png'} alt={'Machine contains ' + type + ' units'} height={24} width={24} />
-)
-
-UnitIcon.propTypes = {
- id: PropTypes.string,
- type: PropTypes.string,
-}
-
-function MachineComponent({ machine, onClick }) {
- const hasNoUnits =
- machine.cpus.length + machine.gpus.length + machine.memories.length + machine.storages.length === 0
-
- return (
- <Flex onClick={() => onClick()}>
- {machine.cpus.length > 0 ? <UnitIcon id="cpuModel" type="CPU" /> : undefined}
- {machine.gpus.length > 0 ? <UnitIcon id="gpu" type="GPU" /> : undefined}
- {machine.memories.length > 0 ? <UnitIcon id="memory" type="memory" /> : undefined}
- {machine.storages.length > 0 ? <UnitIcon id="storage" type="storage" /> : undefined}
- {hasNoUnits ? (
- <Label variant="outline" color="orange">
- Machine with no units
- </Label>
- ) : undefined}
- </Flex>
- )
-}
-
-MachineComponent.propTypes = {
- machine: Machine.isRequired,
- onClick: PropTypes.func,
-}
-
-export default MachineComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListComponent.js
deleted file mode 100644
index 02c97730..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListComponent.js
+++ /dev/null
@@ -1,80 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import MachineComponent from './MachineComponent'
-import {
- Badge,
- Button,
- DataList,
- DataListAction,
- DataListCell,
- DataListItem,
- DataListItemCells,
- DataListItemRow,
-} from '@patternfly/react-core'
-import { AngleRightIcon, PlusIcon } from '@patternfly/react-icons'
-import { Machine } from '../../../../shapes'
-
-function MachineListComponent({ machines = [], onSelect, onAdd }) {
- return (
- <DataList aria-label="Rack Units">
- {machines
- .map((machine, index) =>
- machine ? (
- <DataListItem key={index} onClick={() => onSelect(index + 1)}>
- <DataListItemRow>
- <DataListItemCells
- dataListCells={[
- <DataListCell isIcon key="icon">
- <Badge isRead>{index + 1}U</Badge>
- </DataListCell>,
- <DataListCell key="primary content">
- <MachineComponent onClick={() => onSelect(index + 1)} machine={machine} />
- </DataListCell>,
- ]}
- />
- <DataListAction id="goto" aria-label="Goto Machine" aria-labelledby="goto">
- <Button isSmall variant="plain" className="pf-u-p-0">
- <AngleRightIcon />
- </Button>
- </DataListAction>
- </DataListItemRow>
- </DataListItem>
- ) : (
- <DataListItem key={index}>
- <DataListItemRow>
- <DataListItemCells
- dataListCells={[
- <DataListCell isIcon key="icon">
- <Badge isRead>{index + 1}U</Badge>
- </DataListCell>,
- <DataListCell key="add" className="text-secondary">
- Empty Slot
- </DataListCell>,
- ]}
- />
- <DataListAction id="add" aria-label="Add Machine" aria-labelledby="add">
- <Button
- isSmall
- variant="plain"
- className="pf-u-p-0"
- onClick={() => onAdd(index + 1)}
- >
- <PlusIcon />
- </Button>
- </DataListAction>
- </DataListItemRow>
- </DataListItem>
- )
- )
- .reverse()}
- </DataList>
- )
-}
-
-MachineListComponent.propTypes = {
- machines: PropTypes.arrayOf(Machine),
- onSelect: PropTypes.func.isRequired,
- onAdd: PropTypes.func.isRequired,
-}
-
-export default MachineListComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListContainer.js
deleted file mode 100644
index e1914730..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/MachineListContainer.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React, { useMemo } from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import MachineListComponent from './MachineListComponent'
-import { goFromRackToMachine } from '../../../../redux/actions/interaction-level'
-import { addMachine } from '../../../../redux/actions/topology/rack'
-
-function MachineListContainer({ tileId, ...props }) {
- const rack = useSelector((state) => state.topology.racks[state.topology.tiles[tileId].rack])
- const machines = useSelector((state) => rack.machines.map((id) => state.topology.machines[id]))
- const machinesNull = useMemo(() => {
- const res = Array(rack.capacity).fill(null)
- for (const machine of machines) {
- res[machine.position - 1] = machine
- }
- return res
- }, [rack, machines])
- const dispatch = useDispatch()
-
- return (
- <MachineListComponent
- {...props}
- machines={machinesNull}
- onAdd={(index) => dispatch(addMachine(rack.id, index))}
- onSelect={(index) => dispatch(goFromRackToMachine(index))}
- />
- )
-}
-
-MachineListContainer.propTypes = {
- tileId: PropTypes.string.isRequired,
-}
-
-export default MachineListContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackNameContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackNameContainer.js
deleted file mode 100644
index c3422318..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackNameContainer.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import NameComponent from '../NameComponent'
-import { editRackName } from '../../../../redux/actions/topology/rack'
-
-const RackNameContainer = ({ tileId }) => {
- const { name: rackName, id } = useSelector((state) => state.topology.racks[state.topology.tiles[tileId].rack])
- const dispatch = useDispatch()
- const callback = (name) => {
- if (name) {
- dispatch(editRackName(id, name))
- }
- }
- return <NameComponent name={rackName} onEdit={callback} />
-}
-
-RackNameContainer.propTypes = {
- tileId: PropTypes.string.isRequired,
-}
-
-export default RackNameContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.js
deleted file mode 100644
index cb7d3b68..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { machineListContainer, sidebarContainer } from './RackSidebar.module.css'
-import RackNameContainer from './RackNameContainer'
-import AddPrefab from './AddPrefab'
-import DeleteRackContainer from './DeleteRackContainer'
-import MachineListContainer from './MachineListContainer'
-import {
- Skeleton,
- TextContent,
- TextList,
- TextListItem,
- TextListItemVariants,
- TextListVariants,
- Title,
-} from '@patternfly/react-core'
-import { useSelector } from 'react-redux'
-
-function RackSidebar({ tileId }) {
- const rack = useSelector((state) => state.topology.racks[state.topology.tiles[tileId].rack])
-
- return (
- <div className={sidebarContainer}>
- <TextContent>
- <Title headingLevel="h2">Details</Title>
- <TextList component={TextListVariants.dl}>
- <TextListItem
- component={TextListItemVariants.dt}
- className="pf-u-display-inline-flex pf-u-align-items-center"
- >
- Name
- </TextListItem>
- <TextListItem component={TextListItemVariants.dd}>
- <RackNameContainer tileId={tileId} />
- </TextListItem>
- <TextListItem component={TextListItemVariants.dt}>Capacity</TextListItem>
- <TextListItem component={TextListItemVariants.dd}>
- {rack?.capacity ?? <Skeleton screenreaderText="Loading rack" />}
- </TextListItem>
- </TextList>
- <Title headingLevel="h2">Actions</Title>
- <AddPrefab tileId={tileId} />
- <DeleteRackContainer tileId={tileId} />
-
- <Title headingLevel="h2">Slots</Title>
- </TextContent>
- <div className={machineListContainer}>
- <MachineListContainer tileId={tileId} />
- </div>
- </div>
- )
-}
-
-RackSidebar.propTypes = {
- tileId: PropTypes.string.isRequired,
-}
-
-export default RackSidebar
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.module.css b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.module.css
deleted file mode 100644
index f4c8829f..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/rack/RackSidebar.module.css
+++ /dev/null
@@ -1,14 +0,0 @@
-.sidebarContainer {
- display: flex;
- flex-direction: column;
-
- height: 100%;
-}
-
-.machineListContainer {
- overflow-y: auto;
-
- flex: 1 0 300px;
-
- margin-top: 10px;
-}
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/DeleteRoomContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/DeleteRoomContainer.js
deleted file mode 100644
index 29b8f78a..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/DeleteRoomContainer.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React, { useState } from 'react'
-import { useDispatch } from 'react-redux'
-import ConfirmationModal from '../../../util/modals/ConfirmationModal'
-import { deleteRoom } from '../../../../redux/actions/topology/room'
-import TrashIcon from '@patternfly/react-icons/dist/js/icons/trash-icon'
-import { Button } from '@patternfly/react-core'
-
-function DeleteRoomContainer({ roomId }) {
- const dispatch = useDispatch()
- const [isVisible, setVisible] = useState(false)
- const callback = (isConfirmed) => {
- if (isConfirmed) {
- dispatch(deleteRoom(roomId))
- }
- setVisible(false)
- }
- return (
- <>
- <Button variant="danger" icon={<TrashIcon />} isBlock onClick={() => setVisible(true)}>
- Delete this room
- </Button>
- <ConfirmationModal
- title="Delete this room"
- message="Are you sure you want to delete this room?"
- isOpen={isVisible}
- callback={callback}
- />
- </>
- )
-}
-
-DeleteRoomContainer.propTypes = {
- roomId: PropTypes.string.isRequired,
-}
-
-export default DeleteRoomContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/EditRoomContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/EditRoomContainer.js
deleted file mode 100644
index 7a278cd6..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/EditRoomContainer.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { finishRoomEdit, startRoomEdit } from '../../../../redux/actions/topology/building'
-import CheckIcon from '@patternfly/react-icons/dist/js/icons/check-icon'
-import PencilAltIcon from '@patternfly/react-icons/dist/js/icons/pencil-alt-icon'
-import { Button } from '@patternfly/react-core'
-
-function EditRoomContainer({ roomId }) {
- const isEditing = useSelector((state) => state.construction.currentRoomInConstruction !== '-1')
- const isInRackConstructionMode = useSelector((state) => state.construction.inRackConstructionMode)
-
- const dispatch = useDispatch()
- const onEdit = () => dispatch(startRoomEdit(roomId))
- const onFinish = () => dispatch(finishRoomEdit())
-
- return isEditing ? (
- <Button variant="tertiary" icon={<CheckIcon />} isBlock onClick={onFinish} className="pf-u-mb-sm">
- Finish editing room
- </Button>
- ) : (
- <Button
- variant="tertiary"
- icon={<PencilAltIcon />}
- isBlock
- disabled={isInRackConstructionMode}
- onClick={() => (isInRackConstructionMode ? undefined : onEdit())}
- className="pf-u-mb-sm"
- >
- Edit the tiles of this room
- </Button>
- )
-}
-
-EditRoomContainer.propTypes = {
- roomId: PropTypes.string.isRequired,
-}
-
-export default EditRoomContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionComponent.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionComponent.js
deleted file mode 100644
index a384d5d5..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionComponent.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import { Button } from '@patternfly/react-core'
-import { PlusIcon, TimesIcon } from '@patternfly/react-icons'
-
-const RackConstructionComponent = ({ onStart, onStop, inRackConstructionMode, isEditingRoom }) => {
- if (inRackConstructionMode) {
- return (
- <Button isBlock={true} icon={<TimesIcon />} onClick={onStop} className="pf-u-mb-sm">
- Stop rack construction
- </Button>
- )
- }
-
- return (
- <Button
- icon={<PlusIcon />}
- isBlock
- isDisabled={isEditingRoom}
- onClick={() => (isEditingRoom ? undefined : onStart())}
- className="pf-u-mb-sm"
- >
- Start rack construction
- </Button>
- )
-}
-
-RackConstructionComponent.propTypes = {
- onStart: PropTypes.func,
- onStop: PropTypes.func,
- inRackConstructionMode: PropTypes.bool,
- isEditingRoom: PropTypes.bool,
-}
-
-export default RackConstructionComponent
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionContainer.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionContainer.js
deleted file mode 100644
index e04287a5..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RackConstructionContainer.js
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { startRackConstruction, stopRackConstruction } from '../../../../redux/actions/topology/room'
-import RackConstructionComponent from './RackConstructionComponent'
-
-function RackConstructionContainer(props) {
- const isRackConstructionMode = useSelector((state) => state.construction.inRackConstructionMode)
- const isEditingRoom = useSelector((state) => state.construction.currentRoomInConstruction !== '-1')
-
- const dispatch = useDispatch()
- const onStart = () => dispatch(startRackConstruction())
- const onStop = () => dispatch(stopRackConstruction())
- return (
- <RackConstructionComponent
- {...props}
- inRackConstructionMode={isRackConstructionMode}
- isEditingRoom={isEditingRoom}
- onStart={onStart}
- onStop={onStop}
- />
- )
-}
-
-export default RackConstructionContainer
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomName.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomName.js
deleted file mode 100644
index 72d45bea..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomName.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import NameComponent from '../NameComponent'
-import { editRoomName } from '../../../../redux/actions/topology/room'
-
-function RoomName({ roomId }) {
- const { name: roomName, id } = useSelector((state) => state.topology.rooms[roomId])
- const dispatch = useDispatch()
- const callback = (name) => {
- if (name) {
- dispatch(editRoomName(id, name))
- }
- }
- return <NameComponent name={roomName} onEdit={callback} />
-}
-
-RoomName.propTypes = {
- roomId: PropTypes.string.isRequired,
-}
-
-export default RoomName
diff --git a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomSidebar.js b/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomSidebar.js
deleted file mode 100644
index 6ad489e0..00000000
--- a/opendc-web/opendc-web-ui/src/components/topologies/sidebar/room/RoomSidebar.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import RoomName from './RoomName'
-import RackConstructionContainer from './RackConstructionContainer'
-import EditRoomContainer from './EditRoomContainer'
-import DeleteRoomContainer from './DeleteRoomContainer'
-import {
- TextContent,
- TextList,
- TextListItem,
- TextListItemVariants,
- TextListVariants,
- Title,
-} from '@patternfly/react-core'
-
-const RoomSidebar = ({ roomId }) => {
- return (
- <TextContent>
- <Title headingLevel="h2">Details</Title>
- <TextList component={TextListVariants.dl}>
- <TextListItem
- component={TextListItemVariants.dt}
- className="pf-u-display-inline-flex pf-u-align-items-center"
- >
- Name
- </TextListItem>
- <TextListItem component={TextListItemVariants.dd}>
- <RoomName roomId={roomId} />
- </TextListItem>
- </TextList>
- <Title headingLevel="h2">Construction</Title>
- <RackConstructionContainer />
- <EditRoomContainer roomId={roomId} />
- <DeleteRoomContainer roomId={roomId} />
- </TextContent>
- )
-}
-
-RoomSidebar.propTypes = {
- roomId: PropTypes.string.isRequired,
-}
-
-export default RoomSidebar
diff --git a/opendc-web/opendc-web-ui/src/components/util/TableEmptyState.js b/opendc-web/opendc-web-ui/src/components/util/TableEmptyState.js
deleted file mode 100644
index 9d16ffbb..00000000
--- a/opendc-web/opendc-web-ui/src/components/util/TableEmptyState.js
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import { Bullseye, EmptyState, EmptyStateBody, EmptyStateIcon, Spinner, Title } from '@patternfly/react-core'
-import { SearchIcon, CubesIcon } from '@patternfly/react-icons'
-import { Status } from '../../shapes'
-
-function TableEmptyState({
- status,
- isFiltering,
- loadingTitle = 'Loading',
- emptyTitle = 'No results found',
- emptyText = 'No results found of this type.',
- emptyAction = '',
-}) {
- if (status === 'loading') {
- return (
- <Bullseye>
- <EmptyState variant="xs">
- <EmptyStateIcon variant="container" component={Spinner} />
- <Title headingLevel="h4" size="md">
- {loadingTitle}
- </Title>
- </EmptyState>
- </Bullseye>
- )
- } else if (status === 'error') {
- return (
- <EmptyState variant="xs">
- <Title headingLevel="h4" size="md">
- Unable to connect
- </Title>
- <EmptyStateBody>
- There was an error retrieving data. Check your connection and try again.
- </EmptyStateBody>
- </EmptyState>
- )
- } else if (status === 'idle') {
- return (
- <EmptyState variant="xs">
- <EmptyStateIcon icon={CubesIcon} />
- <Title headingLevel="h4" size="md">
- {emptyTitle}
- </Title>
- <EmptyStateBody>No results available at this moment.</EmptyStateBody>
- </EmptyState>
- )
- } else if (isFiltering) {
- return (
- <EmptyState variant="xs">
- <EmptyStateIcon icon={SearchIcon} />
- <Title headingLevel="h4" size="md">
- No results found
- </Title>
- <EmptyStateBody>
- No results match this filter criteria. Remove all filters or clear all filters to show results.
- </EmptyStateBody>
- </EmptyState>
- )
- }
-
- return (
- <EmptyState variant="xs">
- <EmptyStateIcon icon={CubesIcon} />
- <Title headingLevel="h4" size="md">
- {emptyTitle}
- </Title>
- <EmptyStateBody>{emptyText}</EmptyStateBody>
- {emptyAction}
- </EmptyState>
- )
-}
-
-TableEmptyState.propTypes = {
- status: Status.isRequired,
- isFiltering: PropTypes.bool,
- loadingTitle: PropTypes.string,
- emptyTitle: PropTypes.string,
- emptyText: PropTypes.string,
- emptyAction: PropTypes.node,
-}
-
-export default TableEmptyState
diff --git a/opendc-web/opendc-web-ui/src/components/util/modals/ConfirmationModal.js b/opendc-web/opendc-web-ui/src/components/util/modals/ConfirmationModal.js
deleted file mode 100644
index f6e1c98b..00000000
--- a/opendc-web/opendc-web-ui/src/components/util/modals/ConfirmationModal.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-import Modal from './Modal'
-
-function ConfirmationModal({ title, message, isOpen, callback }) {
- return (
- <Modal
- title={title}
- isOpen={isOpen}
- onSubmit={() => callback(true)}
- onCancel={() => callback(false)}
- submitButtonType="danger"
- submitButtonText="Confirm"
- >
- {message}
- </Modal>
- )
-}
-
-ConfirmationModal.propTypes = {
- title: PropTypes.string.isRequired,
- message: PropTypes.string.isRequired,
- isOpen: PropTypes.bool.isRequired,
- callback: PropTypes.func.isRequired,
-}
-
-export default ConfirmationModal
diff --git a/opendc-web/opendc-web-ui/src/components/util/modals/Modal.js b/opendc-web/opendc-web-ui/src/components/util/modals/Modal.js
deleted file mode 100644
index d4577062..00000000
--- a/opendc-web/opendc-web-ui/src/components/util/modals/Modal.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react'
-import PropTypes from 'prop-types'
-import { Button, Modal as PModal, ModalVariant } from '@patternfly/react-core'
-
-function Modal({ children, title, isOpen, onSubmit, onCancel, submitButtonType, submitButtonText }) {
- const actions = [
- <Button variant={submitButtonType} onClick={onSubmit} key="confirm">
- {submitButtonText}
- </Button>,
- <Button variant="link" onClick={onCancel} key="cancel">
- Cancel
- </Button>,
- ]
-
- return (
- <PModal variant={ModalVariant.small} isOpen={isOpen} onClose={onCancel} title={title} actions={actions}>
- {children}
- </PModal>
- )
-}
-
-Modal.propTypes = {
- title: PropTypes.string.isRequired,
- isOpen: PropTypes.bool,
- onSubmit: PropTypes.func.isRequired,
- onCancel: PropTypes.func.isRequired,
- submitButtonType: PropTypes.string,
- submitButtonText: PropTypes.string,
- children: PropTypes.node,
-}
-
-Modal.defaultProps = {
- submitButtonType: 'primary',
- submitButtonText: 'Save',
- isOpen: false,
-}
-
-export default Modal
diff --git a/opendc-web/opendc-web-ui/src/components/util/modals/TextInputModal.js b/opendc-web/opendc-web-ui/src/components/util/modals/TextInputModal.js
deleted file mode 100644
index 392a729e..00000000
--- a/opendc-web/opendc-web-ui/src/components/util/modals/TextInputModal.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import PropTypes from 'prop-types'
-import React, { useRef, useState } from 'react'
-import Modal from './Modal'
-import { Form, FormGroup, TextInput } from '@patternfly/react-core'
-
-function TextInputModal({ title, label, isOpen, callback, initialValue }) {
- const textInput = useRef(null)
- const [isSubmitted, setSubmitted] = useState(false)
- const [isValid, setValid] = useState(true)
-
- const resetState = () => {
- textInput.current.value = ''
- setSubmitted(false)
- setValid(false)
- }
- const onSubmit = (event) => {
- const value = textInput.current.value
- setSubmitted(true)
-
- if (event) {
- event.preventDefault()
- }
-
- if (!value) {
- setValid(false)
- return false
- }
-
- callback(value)
- resetState()
- return true
- }
- const onCancel = () => {
- callback(undefined)
- resetState()
- }
-
- return (
- <Modal title={title} isOpen={isOpen} onSubmit={onSubmit} onCancel={onCancel}>
- <Form onSubmit={onSubmit}>
- <FormGroup
- label={label}
- fieldId="text-input"
- isRequired
- validated={isSubmitted && !isValid ? 'error' : 'default'}
- helperTextInvalid="This field cannot be empty"
- >
- <TextInput
- id="text-input"
- name="text-input"
- isRequired
- type="text"
- ref={textInput}
- defaultValue={initialValue}
- />
- </FormGroup>
- </Form>
- </Modal>
- )
-}
-
-TextInputModal.propTypes = {
- title: PropTypes.string.isRequired,
- label: PropTypes.string.isRequired,
- isOpen: PropTypes.bool.isRequired,
- callback: PropTypes.func.isRequired,
- initialValue: PropTypes.string,
-}
-
-export default TextInputModal
diff --git a/opendc-web/opendc-web-ui/src/config.js b/opendc-web/opendc-web-ui/src/config.js
deleted file mode 100644
index 52952d69..00000000
--- a/opendc-web/opendc-web-ui/src/config.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * URL to OpenDC API.
- */
-export const apiUrl = process.env.NEXT_PUBLIC_API_BASE_URL
-
-/**
- * Authentication configuration.
- */
-export const auth = {
- domain: process.env.NEXT_PUBLIC_AUTH0_DOMAIN,
- clientId: process.env.NEXT_PUBLIC_AUTH0_CLIENT_ID,
- audience: process.env.NEXT_PUBLIC_AUTH0_AUDIENCE,
- redirectUri: global.window && global.window.location.origin,
-}
-
-/**
- * Sentry DSN for web frontend.
- */
-export const sentryDsn = process.env.NEXT_PUBLIC_SENTRY_DSN
diff --git a/opendc-web/opendc-web-ui/src/data/experiments.js b/opendc-web/opendc-web-ui/src/data/experiments.js
deleted file mode 100644
index ca8912a2..00000000
--- a/opendc-web/opendc-web-ui/src/data/experiments.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useQuery } from 'react-query'
-import { fetchTraces } from '../api/traces'
-import { fetchSchedulers } from '../api/schedulers'
-
-/**
- * Configure the query defaults for the experiment endpoints.
- */
-export function configureExperimentClient(queryClient, auth) {
- queryClient.setQueryDefaults('traces', { queryFn: () => fetchTraces(auth) })
- queryClient.setQueryDefaults('schedulers', { queryFn: () => fetchSchedulers(auth) })
-}
-
-/**
- * Return the available traces to experiment with.
- */
-export function useTraces(options) {
- return useQuery('traces', options)
-}
-
-/**
- * Return the available schedulers to experiment with.
- */
-export function useSchedulers(options) {
- return useQuery('schedulers', options)
-}
diff --git a/opendc-web/opendc-web-ui/src/data/project.js b/opendc-web/opendc-web-ui/src/data/project.js
deleted file mode 100644
index 60a8fab6..00000000
--- a/opendc-web/opendc-web-ui/src/data/project.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useQuery, useMutation } from 'react-query'
-import { addProject, deleteProject, fetchProject, fetchProjects } from '../api/projects'
-import { addPortfolio, deletePortfolio, fetchPortfolio, fetchPortfolios } from '../api/portfolios'
-import { addScenario, deleteScenario, fetchScenario } from '../api/scenarios'
-
-/**
- * Configure the query defaults for the project endpoints.
- */
-export function configureProjectClient(queryClient, auth) {
- queryClient.setQueryDefaults('projects', {
- queryFn: ({ queryKey }) => (queryKey.length === 1 ? fetchProjects(auth) : fetchProject(auth, queryKey[1])),
- })
-
- queryClient.setMutationDefaults('addProject', {
- mutationFn: (data) => addProject(auth, data),
- onSuccess: async (result) => {
- queryClient.setQueryData('projects', (old = []) => [...old, result])
- queryClient.setQueryData(['projects', result.id], result)
- },
- })
- queryClient.setMutationDefaults('deleteProject', {
- mutationFn: (id) => deleteProject(auth, id),
- onSuccess: async (result) => {
- queryClient.setQueryData('projects', (old = []) => old.filter((project) => project.id !== result.id))
- queryClient.removeQueries(['projects', result.id])
- },
- })
-
- queryClient.setQueryDefaults('portfolios', {
- queryFn: ({ queryKey }) =>
- queryKey.length === 2 ? fetchPortfolios(auth, queryKey[1]) : fetchPortfolio(auth, queryKey[1], queryKey[2]),
- })
- queryClient.setMutationDefaults('addPortfolio', {
- mutationFn: ({ projectId, ...data }) => addPortfolio(auth, projectId, data),
- onSuccess: async (result) => {
- queryClient.setQueryData(['portfolios', result.project.id], (old = []) => [...old, result])
- queryClient.setQueryData(['portfolios', result.project.id, result.number], result)
- },
- })
- queryClient.setMutationDefaults('deletePortfolio', {
- mutationFn: ({ projectId, number }) => deletePortfolio(auth, projectId, number),
- onSuccess: async (result) => {
- queryClient.setQueryData(['portfolios', result.project.id], (old = []) =>
- old.filter((portfolio) => portfolio.id !== result.id)
- )
- queryClient.removeQueries(['portfolios', result.project.id, result.number])
- },
- })
-
- queryClient.setQueryDefaults('scenarios', {
- queryFn: ({ queryKey }) => fetchScenario(auth, queryKey[1], queryKey[2]),
- })
- queryClient.setMutationDefaults('addScenario', {
- mutationFn: ({ projectId, portfolioNumber, data }) => addScenario(auth, projectId, portfolioNumber, data),
- onSuccess: async (result) => {
- // Register updated scenario in cache
- queryClient.setQueryData(['scenarios', result.project.id, result.id], result)
- queryClient.setQueryData(['portfolios', result.project.id, result.portfolio.number], (old) => ({
- ...old,
- scenarios: [...old.scenarios, result],
- }))
- },
- })
- queryClient.setMutationDefaults('deleteScenario', {
- mutationFn: ({ projectId, number }) => deleteScenario(auth, projectId, number),
- onSuccess: async (result) => {
- queryClient.removeQueries(['scenarios', result.project.id, result.id])
- queryClient.setQueryData(['portfolios', result.project.id, result.portfolio.number], (old) => ({
- ...old,
- scenarios: old?.scenarios?.filter((scenario) => scenario.id !== result.id),
- }))
- },
- })
-}
-
-/**
- * Return the available projects.
- */
-export function useProjects(options = {}) {
- return useQuery('projects', options)
-}
-
-/**
- * Return the project with the specified identifier.
- */
-export function useProject(projectId, options = {}) {
- return useQuery(['projects', projectId], { enabled: !!projectId, ...options })
-}
-
-/**
- * Create a mutation for a new project.
- */
-export function useNewProject() {
- return useMutation('addProject')
-}
-
-/**
- * Create a mutation for deleting a project.
- */
-export function useDeleteProject() {
- return useMutation('deleteProject')
-}
-
-/**
- * Return the portfolio with the specified identifier.
- */
-export function usePortfolio(projectId, portfolioId, options = {}) {
- return useQuery(['portfolios', projectId, portfolioId], { enabled: !!(projectId && portfolioId), ...options })
-}
-
-/**
- * Return the portfolios of the specified project.
- */
-export function usePortfolios(projectId, options = {}) {
- return useQuery(['portfolios', projectId], { enabled: !!projectId, ...options })
-}
-
-/**
- * Create a mutation for a new portfolio.
- */
-export function useNewPortfolio() {
- return useMutation('addPortfolio')
-}
-
-/**
- * Create a mutation for deleting a portfolio.
- */
-export function useDeletePortfolio() {
- return useMutation('deletePortfolio')
-}
-
-/**
- * Create a mutation for a new scenario.
- */
-export function useNewScenario() {
- return useMutation('addScenario')
-}
-
-/**
- * Create a mutation for deleting a scenario.
- */
-export function useDeleteScenario() {
- return useMutation('deleteScenario')
-}
diff --git a/opendc-web/opendc-web-ui/src/data/query.js b/opendc-web/opendc-web-ui/src/data/query.js
deleted file mode 100644
index 3e5423b9..00000000
--- a/opendc-web/opendc-web-ui/src/data/query.js
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useMemo } from 'react'
-import { QueryClient } from 'react-query'
-import { useAuth } from '../auth'
-import { configureExperimentClient } from './experiments'
-import { configureProjectClient } from './project'
-import { configureTopologyClient } from './topology'
-import { configureUserClient } from './user'
-
-let queryClient
-
-function createQueryClient(auth) {
- const client = new QueryClient()
- configureProjectClient(client, auth)
- configureExperimentClient(client, auth)
- configureTopologyClient(client, auth)
- configureUserClient(client, auth)
- return client
-}
-
-function initializeQueryClient(auth) {
- const _queryClient = queryClient ?? createQueryClient(auth)
-
- // For SSG and SSR always create a new query client
- if (typeof window === 'undefined') return _queryClient
- // Create the query client once in the client
- if (!queryClient) queryClient = _queryClient
-
- return _queryClient
-}
-
-/**
- * Obtain a cached query client.
- */
-export function useNewQueryClient() {
- const auth = useAuth()
- return useMemo(() => initializeQueryClient(auth), []) // eslint-disable-line react-hooks/exhaustive-deps
-}
diff --git a/opendc-web/opendc-web-ui/src/data/topology.js b/opendc-web/opendc-web-ui/src/data/topology.js
deleted file mode 100644
index d5e624d5..00000000
--- a/opendc-web/opendc-web-ui/src/data/topology.js
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useQuery, useMutation } from 'react-query'
-import { addTopology, deleteTopology, fetchTopologies, fetchTopology, updateTopology } from '../api/topologies'
-
-/**
- * Configure the query defaults for the topology endpoints.
- */
-export function configureTopologyClient(queryClient, auth) {
- queryClient.setQueryDefaults('topologies', {
- queryFn: ({ queryKey }) =>
- queryKey.length === 2 ? fetchTopologies(auth, queryKey[1]) : fetchTopology(auth, queryKey[1], queryKey[2]),
- })
-
- queryClient.setMutationDefaults('addTopology', {
- mutationFn: ({ projectId, ...data }) => addTopology(auth, projectId, data),
- onSuccess: (result) => {
- queryClient.setQueryData(['topologies', result.project.id], (old = []) => [...old, result])
- queryClient.setQueryData(['topologies', result.project.id, result.number], result)
- },
- })
- queryClient.setMutationDefaults('updateTopology', {
- mutationFn: (data) => updateTopology(auth, data),
- onSuccess: (result) => {
- queryClient.setQueryData(['topologies', result.project.id], (old = []) =>
- old.map((topology) => (topology.id === result.id ? result : topology))
- )
- queryClient.setQueryData(['topologies', result.project.id, result.number], result)
- },
- })
- queryClient.setMutationDefaults('deleteTopology', {
- mutationFn: ({ projectId, number }) => deleteTopology(auth, projectId, number),
- onSuccess: (result) => {
- queryClient.setQueryData(['topologies', result.project.id], (old = []) =>
- old.filter((topology) => topology.id !== result.id)
- )
- queryClient.removeQueries(['topologies', result.project.id, result.number])
- },
- })
-}
-
-/**
- * Fetch the topology with the specified identifier for the specified project.
- */
-export function useTopology(projectId, topologyId, options = {}) {
- return useQuery(['topologies', projectId, topologyId], { enabled: !!(projectId && topologyId), ...options })
-}
-
-/**
- * Fetch all topologies of the specified project.
- */
-export function useTopologies(projectId, options = {}) {
- return useQuery(['topologies', projectId], { enabled: !!projectId, ...options })
-}
-
-/**
- * Create a mutation for a new topology.
- */
-export function useNewTopology() {
- return useMutation('addTopology')
-}
-
-/**
- * Create a mutation for deleting a topology.
- */
-export function useDeleteTopology(options = {}) {
- return useMutation('deleteTopology', options)
-}
diff --git a/opendc-web/opendc-web-ui/src/data/user.js b/opendc-web/opendc-web-ui/src/data/user.js
deleted file mode 100644
index 97c0e1e2..00000000
--- a/opendc-web/opendc-web-ui/src/data/user.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useQuery } from 'react-query'
-import { fetchUser } from '../api/users'
-
-/**
- * Configure the query defaults for the user client.
- */
-export function configureUserClient(queryClient, auth) {
- queryClient.setQueryDefaults('user', {
- queryFn: () => fetchUser(auth),
- })
-}
-
-/**
- * Fetch the user data on the server.
- */
-export default function useUser(options = {}) {
- return useQuery('user', options)
-}
diff --git a/opendc-web/opendc-web-ui/src/pages/404.js b/opendc-web/opendc-web-ui/src/pages/404.js
deleted file mode 100644
index 0939bc56..00000000
--- a/opendc-web/opendc-web-ui/src/pages/404.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React from 'react'
-import Head from 'next/head'
-import { AppPage } from '../components/AppPage'
-import {
- Bullseye,
- EmptyState,
- EmptyStateBody,
- EmptyStateIcon,
- PageSection,
- PageSectionVariants,
- Title,
-} from '@patternfly/react-core'
-import { UnknownIcon } from '@patternfly/react-icons'
-
-const NotFound = () => {
- return (
- <AppPage>
- <Head>
- <title>Page Not Found - OpenDC</title>
- </Head>
- <PageSection variant={PageSectionVariants.light}>
- <Bullseye>
- <EmptyState>
- <EmptyStateIcon variant="container" component={UnknownIcon} />
- <Title size="lg" headingLevel="h4">
- 404: That page does not exist
- </Title>
- <EmptyStateBody>
- The requested page is not found. Try refreshing the page if it was recently added.
- </EmptyStateBody>
- </EmptyState>
- </Bullseye>
- </PageSection>
- </AppPage>
- )
-}
-
-export default NotFound
diff --git a/opendc-web/opendc-web-ui/src/pages/_app.js b/opendc-web/opendc-web-ui/src/pages/_app.js
deleted file mode 100644
index 62ce0539..00000000
--- a/opendc-web/opendc-web-ui/src/pages/_app.js
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-import Head from 'next/head'
-import Script from 'next/script'
-import { Provider } from 'react-redux'
-import { useNewQueryClient } from '../data/query'
-import { useStore } from '../redux'
-import { AuthProvider, useRequireAuth } from '../auth'
-import * as Sentry from '@sentry/react'
-import { Integrations } from '@sentry/tracing'
-import { QueryClientProvider } from 'react-query'
-import { sentryDsn } from '../config'
-
-import '@patternfly/react-core/dist/styles/base.css'
-import '@patternfly/react-styles/css/utilities/Alignment/alignment.css'
-import '@patternfly/react-styles/css/utilities/BackgroundColor/BackgroundColor.css'
-import '@patternfly/react-styles/css/utilities/BoxShadow/box-shadow.css'
-import '@patternfly/react-styles/css/utilities/Display/display.css'
-import '@patternfly/react-styles/css/utilities/Flex/flex.css'
-import '@patternfly/react-styles/css/utilities/Float/float.css'
-import '@patternfly/react-styles/css/utilities/Sizing/sizing.css'
-import '@patternfly/react-styles/css/utilities/Spacing/spacing.css'
-import '@patternfly/react-styles/css/utilities/Text/text.css'
-import '@patternfly/react-styles/css/components/InlineEdit/inline-edit.css'
-import '../style/index.css'
-
-// This setup is necessary to forward the Auth0 context to the Redux context
-function Inner({ Component, pageProps }) {
- // Force user to be authorized
- useRequireAuth()
-
- const queryClient = useNewQueryClient()
- const store = useStore(pageProps.initialReduxState, { queryClient })
- return (
- <QueryClientProvider client={queryClient}>
- <Provider store={store}>
- <Component {...pageProps} />
- </Provider>
- </QueryClientProvider>
- )
-}
-
-Inner.propTypes = {
- Component: PropTypes.func,
- pageProps: PropTypes.shape({
- initialReduxState: PropTypes.object,
- }).isRequired,
-}
-
-// Initialize Sentry if the user has configured a DSN
-if (process.browser && sentryDsn) {
- Sentry.init({
- environment: process.env.NODE_ENV,
- dsn: sentryDsn,
- integrations: [new Integrations.BrowserTracing()],
- tracesSampleRate: 0.1,
- })
-}
-
-export default function App(props) {
- return (
- <>
- <Head>
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
- <meta name="theme-color" content="#00A6D6" />
- </Head>
- <Sentry.ErrorBoundary fallback={'An error has occurred'}>
- <AuthProvider>
- <Inner {...props} />
- </AuthProvider>
- </Sentry.ErrorBoundary>
- {/* Google Analytics */}
- <Script async src="https://www.googletagmanager.com/gtag/js?id=UA-84285092-3" />
- <Script
- id="gtag"
- dangerouslySetInnerHTML={{
- __html: `
- window.dataLayer = window.dataLayer || [];
- function gtag(){dataLayer.push(arguments);}
- gtag('js', new Date());
- gtag('config', 'UA-84285092-3');
- `,
- }}
- />
- </>
- )
-}
diff --git a/opendc-web/opendc-web-ui/src/pages/_document.js b/opendc-web/opendc-web-ui/src/pages/_document.js
deleted file mode 100644
index 9f84b2ab..00000000
--- a/opendc-web/opendc-web-ui/src/pages/_document.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import Document, { Html, Head, Main, NextScript } from 'next/document'
-
-class OpenDCDocument extends Document {
- render() {
- return (
- <Html lang="en">
- <Head>
- <meta charSet="utf-8" />
- <meta name="theme-color" content="#00A6D6" />
- <meta
- name="description"
- content="Collaborative Datacenter Simulation and Exploration for Everybody"
- />
- <meta name="author" content="@Large Research" />
- <meta
- name="keywords"
- content="OpenDC, Datacenter, Simulation, Simulator, Collaborative, Distributed, Cluster"
- />
- <link rel="manifest" href="/manifest.json" />
- <link rel="shortcut icon" href="/favicon.ico" />
-
- {/* Twitter Card data */}
- <meta name="twitter:card" content="summary" />
- <meta name="twitter:site" content="@LargeResearch" />
- <meta name="twitter:title" content="OpenDC" />
- <meta
- name="twitter:description"
- content="Collaborative Datacenter Simulation and Exploration for Everybody"
- />
- <meta name="twitter:creator" content="@LargeResearch" />
- <meta name="twitter:image" content="http://opendc.org/img/logo.png" />
-
- {/* OpenGraph meta tags */}
- <meta property="og:title" content="OpenDC" />
- <meta property="og:site_name" content="OpenDC" />
- <meta property="og:type" content="website" />
- <meta property="og:image" content="http://opendc.org/img/logo.png" />
- <meta property="og:url" content="http://opendc.org/" />
- <meta
- property="og:description"
- content="OpenDC provides collaborative online datacenter modeling, diverse and effective datacenter simulation, and exploratory datacenter performance feedback."
- />
- <meta property="og:locale" content="en_US" />
- </Head>
- <body>
- <Main />
- <NextScript />
- </body>
- </Html>
- )
- }
-}
-
-export default OpenDCDocument
diff --git a/opendc-web/opendc-web-ui/src/pages/logout.js b/opendc-web/opendc-web-ui/src/pages/logout.js
deleted file mode 100644
index 38d5968e..00000000
--- a/opendc-web/opendc-web-ui/src/pages/logout.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import React from 'react'
-import Head from 'next/head'
-import { AppPage } from '../components/AppPage'
-import { PageSection, PageSectionVariants } from '@patternfly/react-core'
-
-function Logout() {
- return (
- <AppPage>
- <Head>
- <title>Logged Out - OpenDC</title>
- </Head>
- <PageSection variant={PageSectionVariants.light}>Logged out successfully</PageSection>
- </AppPage>
- )
-}
-
-export default Logout
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js
deleted file mode 100644
index 52938bcd..00000000
--- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useRouter } from 'next/router'
-import ProjectOverview from '../../../components/projects/ProjectOverview'
-import { useProject } from '../../../data/project'
-import { AppPage } from '../../../components/AppPage'
-import Head from 'next/head'
-import Link from 'next/link'
-import {
- Breadcrumb,
- BreadcrumbItem,
- PageSection,
- PageSectionVariants,
- Skeleton,
- Text,
- TextContent,
-} from '@patternfly/react-core'
-
-function Project() {
- const router = useRouter()
- const projectId = +router.query['project']
-
- const { data: project } = useProject(+projectId)
-
- const breadcrumb = (
- <Breadcrumb>
- <BreadcrumbItem to="/projects" component={Link}>
- Projects
- </BreadcrumbItem>
- <BreadcrumbItem to={`/projects/${projectId}`} component={Link} isActive>
- Project details
- </BreadcrumbItem>
- </Breadcrumb>
- )
-
- return (
- <AppPage breadcrumb={breadcrumb}>
- <Head>
- <title>{`${project?.name ?? 'Project'} - OpenDC`}</title>
- </Head>
- <PageSection variant={PageSectionVariants.light}>
- <TextContent>
- <Text component="h1">
- {project?.name ?? <Skeleton width="15%" screenreaderText="Loading project" />}
- </Text>
- </TextContent>
- </PageSection>
- <PageSection isFilled>
- <ProjectOverview projectId={projectId} />
- </PageSection>
- </AppPage>
- )
-}
-
-export default Project
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js
deleted file mode 100644
index 5d1e041b..00000000
--- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import dynamic from 'next/dynamic'
-import { useRouter } from 'next/router'
-import Head from 'next/head'
-import Link from 'next/link'
-import React, { useRef } from 'react'
-import {
- Breadcrumb,
- BreadcrumbItem,
- Divider,
- PageSection,
- PageSectionVariants,
- Tab,
- TabContent,
- Tabs,
- TabTitleText,
- Text,
- TextContent,
-} from '@patternfly/react-core'
-import { AppPage } from '../../../../components/AppPage'
-import ContextSelectionSection from '../../../../components/context/ContextSelectionSection'
-import PortfolioSelector from '../../../../components/context/PortfolioSelector'
-import PortfolioOverview from '../../../../components/portfolios/PortfolioOverview'
-import { usePortfolio } from '../../../../data/project'
-
-const PortfolioResults = dynamic(() => import('../../../../components/portfolios/PortfolioResults'), { ssr: false })
-
-/**
- * Page that displays the results in a portfolio.
- */
-function Portfolio() {
- const router = useRouter()
- const projectId = +router.query['project']
- const portfolioNumber = +router.query['portfolio']
-
- const overviewRef = useRef(null)
- const resultsRef = useRef(null)
-
- const { data: portfolio } = usePortfolio(projectId, portfolioNumber)
-
- const breadcrumb = (
- <Breadcrumb>
- <BreadcrumbItem to="/projects" component={Link}>
- Projects
- </BreadcrumbItem>
- <BreadcrumbItem to={`/projects/${projectId}`} component={Link}>
- Project details
- </BreadcrumbItem>
- <BreadcrumbItem to={`/projects/${projectId}/portfolios/${portfolioNumber}`} component={Link} isActive>
- Portfolio
- </BreadcrumbItem>
- </Breadcrumb>
- )
-
- const contextSelectors = (
- <ContextSelectionSection>
- <PortfolioSelector activePortfolio={portfolio} />
- </ContextSelectionSection>
- )
-
- return (
- <AppPage breadcrumb={breadcrumb} contextSelectors={contextSelectors}>
- <Head>
- <title>Portfolio - OpenDC</title>
- </Head>
- <PageSection variant={PageSectionVariants.light}>
- <TextContent>
- <Text component="h1">Portfolio</Text>
- </TextContent>
- </PageSection>
- <PageSection type="tabs" variant={PageSectionVariants.light} stickyOnBreakpoint={{ default: 'top' }}>
- <Divider component="div" />
- <Tabs defaultActiveKey={0} className="pf-m-page-insets">
- <Tab
- eventKey={0}
- title={<TabTitleText>Overview</TabTitleText>}
- tabContentId="overview"
- tabContentRef={overviewRef}
- />
- <Tab
- eventKey={1}
- title={<TabTitleText>Results</TabTitleText>}
- tabContentId="results"
- tabContentRef={resultsRef}
- />
- </Tabs>
- </PageSection>
- <PageSection isFilled>
- <TabContent eventKey={0} id="overview" ref={overviewRef} aria-label="Overview tab">
- <PortfolioOverview projectId={projectId} portfolioId={portfolioNumber} />
- </TabContent>
- <TabContent eventKey={1} id="results" ref={resultsRef} aria-label="Results tab" hidden>
- <PortfolioResults projectId={projectId} portfolioId={portfolioNumber} />
- </TabContent>
- </PageSection>
- </AppPage>
- )
-}
-
-export default Portfolio
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js
deleted file mode 100644
index 48359365..00000000
--- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import dynamic from 'next/dynamic'
-import { useRouter } from 'next/router'
-import Head from 'next/head'
-import Link from 'next/link'
-import ContextSelectionSection from '../../../../components/context/ContextSelectionSection'
-import TopologySelector from '../../../../components/context/TopologySelector'
-import TopologyOverview from '../../../../components/topologies/TopologyOverview'
-import { useDispatch } from 'react-redux'
-import React, { useEffect, useState } from 'react'
-import { AppPage } from '../../../../components/AppPage'
-import {
- Breadcrumb,
- BreadcrumbItem,
- Divider,
- PageSection,
- PageSectionVariants,
- Tab,
- TabContent,
- Tabs,
- TabTitleText,
- Text,
- TextContent,
-} from '@patternfly/react-core'
-import { useTopology } from '../../../../data/topology'
-import { goToRoom } from '../../../../redux/actions/interaction-level'
-import { openTopology } from '../../../../redux/actions/topology'
-
-const TopologyMap = dynamic(() => import('../../../../components/topologies/TopologyMap'), { ssr: false })
-
-/**
- * Page that displays a datacenter topology.
- */
-function Topology() {
- const router = useRouter()
- const projectId = +router.query['project']
- const topologyNumber = +router.query['topology']
-
- const { data: topology } = useTopology(projectId, topologyNumber)
-
- const dispatch = useDispatch()
- useEffect(() => {
- if (topologyNumber) {
- dispatch(openTopology(projectId, topologyNumber))
- }
- }, [projectId, topologyNumber, dispatch])
-
- const [activeTab, setActiveTab] = useState('overview')
-
- const breadcrumb = (
- <Breadcrumb>
- <BreadcrumbItem to="/projects" component={Link}>
- Projects
- </BreadcrumbItem>
- <BreadcrumbItem to={`/projects/${projectId}`} component={Link}>
- Project details
- </BreadcrumbItem>
- <BreadcrumbItem to={`/projects/${projectId}/topologies/${topologyNumber}`} component={Link} isActive>
- Topology
- </BreadcrumbItem>
- </Breadcrumb>
- )
-
- const contextSelectors = (
- <ContextSelectionSection>
- <TopologySelector activeTopology={topology} />
- </ContextSelectionSection>
- )
-
- return (
- <AppPage breadcrumb={breadcrumb} contextSelectors={contextSelectors}>
- <Head>
- <title>{`${topology?.name ?? 'Topologies'} - OpenDC`}</title>
- </Head>
- <PageSection variant={PageSectionVariants.light}>
- <TextContent>
- <Text component="h1">Topology</Text>
- </TextContent>
- </PageSection>
- <PageSection type="none" variant={PageSectionVariants.light} className="pf-c-page__main-tabs" sticky="top">
- <Divider component="div" />
- <Tabs
- activeKey={activeTab}
- onSelect={(_, tabIndex) => setActiveTab(tabIndex)}
- className="pf-m-page-insets"
- >
- <Tab eventKey="overview" title={<TabTitleText>Overview</TabTitleText>} tabContentId="overview" />
- <Tab
- eventKey="floor-plan"
- title={<TabTitleText>Floor Plan</TabTitleText>}
- tabContentId="floor-plan"
- />
- </Tabs>
- </PageSection>
- <PageSection padding={activeTab === 'floor-plan' && { default: 'noPadding' }} isFilled>
- <TabContent id="overview" aria-label="Overview tab" hidden={activeTab !== 'overview'}>
- <TopologyOverview
- projectId={projectId}
- topologyNumber={topologyNumber}
- onSelect={(type, obj) => {
- if (type === 'room') {
- dispatch(goToRoom(obj.id))
- setActiveTab('floor-plan')
- }
- }}
- />
- </TabContent>
- <TabContent
- id="floor-plan"
- aria-label="Floor Plan tab"
- className="pf-u-h-100"
- hidden={activeTab !== 'floor-plan'}
- >
- <TopologyMap />
- </TabContent>
- </PageSection>
- </AppPage>
- )
-}
-
-export default Topology
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/index.js b/opendc-web/opendc-web-ui/src/pages/projects/index.js
deleted file mode 100644
index 97ff105c..00000000
--- a/opendc-web/opendc-web-ui/src/pages/projects/index.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { PlusIcon } from '@patternfly/react-icons'
-import React, { useMemo, useState } from 'react'
-import Head from 'next/head'
-import ProjectFilterPanel from '../../components/projects/FilterPanel'
-import { AppPage } from '../../components/AppPage'
-import {
- PageSection,
- PageSectionVariants,
- Title,
- Toolbar,
- ToolbarItem,
- ToolbarContent,
- Button,
- TextContent,
- Text,
-} from '@patternfly/react-core'
-import ProjectCollection from '../../components/projects/ProjectCollection'
-import TextInputModal from '../../components/util/modals/TextInputModal'
-import { useProjects, useDeleteProject, useNewProject } from '../../data/project'
-
-const getVisibleProjects = (projects, filter) => {
- switch (filter) {
- case 'SHOW_ALL':
- return projects
- case 'SHOW_OWN':
- return projects.filter((project) => project.role === 'OWNER')
- case 'SHOW_SHARED':
- return projects.filter((project) => project.role !== 'OWNER')
- default:
- return projects
- }
-}
-
-function Projects() {
- const { status, data: projects } = useProjects()
- const [filter, setFilter] = useState('SHOW_ALL')
- const visibleProjects = useMemo(() => getVisibleProjects(projects ?? [], filter), [projects, filter])
-
- const { mutate: deleteProject } = useDeleteProject()
- const { mutate: addProject } = useNewProject()
-
- const [isProjectCreationModalVisible, setProjectCreationModalVisible] = useState(false)
- const onProjectCreation = (name) => {
- if (name) {
- addProject({ name })
- }
- setProjectCreationModalVisible(false)
- }
-
- return (
- <AppPage>
- <Head>
- <title>My Projects - OpenDC</title>
- </Head>
- <PageSection variant={PageSectionVariants.light} isFilled>
- <div className="pf-u-mx-auto pf-u-max-width" style={{ '--pf-u-max-width--MaxWidth': '100ch' }}>
- <Title className="pf-u-mt-xl-on-md" headingLevel="h1" size="4xl">
- Welcome
- </Title>
- <TextContent>
- <Text component="p">Find all your personal and shared projects</Text>
- </TextContent>
- <Toolbar inset={{ default: 'insetNone' }}>
- <ToolbarContent>
- <ToolbarItem>
- <ProjectFilterPanel onSelect={setFilter} activeFilter={filter} />
- </ToolbarItem>
- <ToolbarItem alignment={{ default: 'alignRight' }}>
- <Button icon={<PlusIcon />} onClick={() => setProjectCreationModalVisible(true)}>
- Create Project
- </Button>
- </ToolbarItem>
- </ToolbarContent>
- </Toolbar>
- <ProjectCollection
- status={status}
- isFiltering={filter !== 'SHOW_ALL'}
- projects={visibleProjects}
- onDelete={(project) => deleteProject(project.id)}
- onCreate={() => setProjectCreationModalVisible(true)}
- />
- <TextInputModal
- title="New Project"
- label="Project name"
- isOpen={isProjectCreationModalVisible}
- callback={onProjectCreation}
- />
- </div>
- </PageSection>
- </AppPage>
- )
-}
-
-export default Projects
diff --git a/opendc-web/opendc-web-ui/src/redux/actions/interaction-level.js b/opendc-web/opendc-web-ui/src/redux/actions/interaction-level.js
deleted file mode 100644
index 8381eeef..00000000
--- a/opendc-web/opendc-web-ui/src/redux/actions/interaction-level.js
+++ /dev/null
@@ -1,57 +0,0 @@
-export const GO_FROM_BUILDING_TO_ROOM = 'GO_FROM_BUILDING_TO_ROOM'
-export const GO_FROM_ROOM_TO_RACK = 'GO_FROM_ROOM_TO_RACK'
-export const GO_FROM_RACK_TO_MACHINE = 'GO_FROM_RACK_TO_MACHINE'
-export const GO_DOWN_ONE_INTERACTION_LEVEL = 'GO_DOWN_ONE_INTERACTION_LEVEL'
-
-export function goToRoom(roomId) {
- return {
- type: GO_FROM_BUILDING_TO_ROOM,
- roomId,
- }
-}
-
-export function goFromBuildingToRoom(roomId) {
- return (dispatch, getState) => {
- const { interactionLevel } = getState()
- if (interactionLevel.mode !== 'BUILDING') {
- return
- }
-
- dispatch({
- type: GO_FROM_BUILDING_TO_ROOM,
- roomId,
- })
- }
-}
-
-export function goFromRoomToRack(tileId) {
- return (dispatch, getState) => {
- const { interactionLevel } = getState()
- if (interactionLevel.mode !== 'ROOM') {
- return
- }
- dispatch({
- type: GO_FROM_ROOM_TO_RACK,
- tileId,
- })
- }
-}
-
-export function goFromRackToMachine(position) {
- return (dispatch, getState) => {
- const { interactionLevel } = getState()
- if (interactionLevel.mode !== 'RACK') {
- return
- }
- dispatch({
- type: GO_FROM_RACK_TO_MACHINE,
- position,
- })
- }
-}
-
-export function goDownOneInteractionLevel() {
- return {
- type: GO_DOWN_ONE_INTERACTION_LEVEL,
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/actions/topology/building.js b/opendc-web/opendc-web-ui/src/redux/actions/topology/building.js
deleted file mode 100644
index c12417b9..00000000
--- a/opendc-web/opendc-web-ui/src/redux/actions/topology/building.js
+++ /dev/null
@@ -1,113 +0,0 @@
-import { v4 as uuid } from 'uuid'
-import { addRoom, deleteRoom } from './room'
-
-export const START_NEW_ROOM_CONSTRUCTION = 'START_NEW_ROOM_CONSTRUCTION'
-export const START_NEW_ROOM_CONSTRUCTION_SUCCEEDED = 'START_NEW_ROOM_CONSTRUCTION_SUCCEEDED'
-export const FINISH_NEW_ROOM_CONSTRUCTION = 'FINISH_NEW_ROOM_CONSTRUCTION'
-export const CANCEL_NEW_ROOM_CONSTRUCTION = 'CANCEL_NEW_ROOM_CONSTRUCTION'
-export const CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED = 'CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED'
-export const START_ROOM_EDIT = 'START_ROOM_EDIT'
-export const FINISH_ROOM_EDIT = 'FINISH_ROOM_EDIT'
-export const ADD_TILE = 'ADD_TILE'
-export const DELETE_TILE = 'DELETE_TILE'
-
-export function startNewRoomConstruction() {
- return (dispatch, getState) => {
- const { topology } = getState()
- const topologyId = topology.root.id
- const room = {
- id: uuid(),
- name: 'Room',
- topologyId,
- tiles: [],
- }
-
- dispatch(addRoom(topologyId, room))
- dispatch(startNewRoomConstructionSucceeded(room.id))
- }
-}
-
-export function startNewRoomConstructionSucceeded(roomId) {
- return {
- type: START_NEW_ROOM_CONSTRUCTION_SUCCEEDED,
- roomId,
- }
-}
-
-export function finishNewRoomConstruction() {
- return (dispatch, getState) => {
- const { topology, construction } = getState()
- if (topology.rooms[construction.currentRoomInConstruction].tiles.length === 0) {
- dispatch(cancelNewRoomConstruction())
- return
- }
-
- dispatch({
- type: FINISH_NEW_ROOM_CONSTRUCTION,
- })
- }
-}
-
-export function cancelNewRoomConstruction() {
- return (dispatch, getState) => {
- const { construction } = getState()
- const roomId = construction.currentRoomInConstruction
- dispatch(deleteRoom(roomId))
- dispatch(cancelNewRoomConstructionSucceeded())
- }
-}
-
-export function cancelNewRoomConstructionSucceeded() {
- return {
- type: CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED,
- }
-}
-
-export function startRoomEdit(roomId) {
- return {
- type: START_ROOM_EDIT,
- roomId: roomId,
- }
-}
-
-export function finishRoomEdit() {
- return {
- type: FINISH_ROOM_EDIT,
- }
-}
-
-export function toggleTileAtLocation(positionX, positionY) {
- return (dispatch, getState) => {
- const { topology, construction } = getState()
-
- const roomId = construction.currentRoomInConstruction
- const tileIds = topology.rooms[roomId].tiles
- for (const tileId of tileIds) {
- if (topology.tiles[tileId].positionX === positionX && topology.tiles[tileId].positionY === positionY) {
- dispatch(deleteTile(tileId))
- return
- }
- }
-
- dispatch(addTile(roomId, positionX, positionY))
- }
-}
-
-export function addTile(roomId, positionX, positionY) {
- return {
- type: ADD_TILE,
- tile: {
- id: uuid(),
- roomId,
- positionX,
- positionY,
- },
- }
-}
-
-export function deleteTile(tileId) {
- return {
- type: DELETE_TILE,
- tileId,
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/actions/topology/index.js b/opendc-web/opendc-web-ui/src/redux/actions/topology/index.js
deleted file mode 100644
index d48af37a..00000000
--- a/opendc-web/opendc-web-ui/src/redux/actions/topology/index.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-export const OPEN_TOPOLOGY = 'OPEN_TOPOLOGY'
-export const STORE_TOPOLOGY = 'STORE_TOPOLOGY'
-
-export function openTopology(projectId, id) {
- return {
- type: OPEN_TOPOLOGY,
- projectId,
- id,
- }
-}
-
-export function storeTopology(topology, entities) {
- return {
- type: STORE_TOPOLOGY,
- topology,
- entities,
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/actions/topology/machine.js b/opendc-web/opendc-web-ui/src/redux/actions/topology/machine.js
deleted file mode 100644
index 93320884..00000000
--- a/opendc-web/opendc-web-ui/src/redux/actions/topology/machine.js
+++ /dev/null
@@ -1,28 +0,0 @@
-export const DELETE_MACHINE = 'DELETE_MACHINE'
-export const ADD_UNIT = 'ADD_UNIT'
-export const DELETE_UNIT = 'DELETE_UNIT'
-
-export function deleteMachine(machineId) {
- return {
- type: DELETE_MACHINE,
- machineId,
- }
-}
-
-export function addUnit(machineId, unitType, unitId) {
- return {
- type: ADD_UNIT,
- machineId,
- unitType,
- unitId,
- }
-}
-
-export function deleteUnit(machineId, unitType, unitId) {
- return {
- type: DELETE_UNIT,
- machineId,
- unitType,
- unitId,
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/actions/topology/rack.js b/opendc-web/opendc-web-ui/src/redux/actions/topology/rack.js
deleted file mode 100644
index 1f65952a..00000000
--- a/opendc-web/opendc-web-ui/src/redux/actions/topology/rack.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { v4 as uuid } from 'uuid'
-
-export const EDIT_RACK_NAME = 'EDIT_RACK_NAME'
-export const DELETE_RACK = 'DELETE_RACK'
-export const ADD_MACHINE = 'ADD_MACHINE'
-
-export function editRackName(rackId, name) {
- return {
- type: EDIT_RACK_NAME,
- name,
- rackId,
- }
-}
-
-export function deleteRack(tileId, rackId) {
- return {
- type: DELETE_RACK,
- rackId,
- tileId,
- }
-}
-
-export function addMachine(rackId, position) {
- return {
- type: ADD_MACHINE,
- machine: {
- id: uuid(),
- rackId,
- position,
- cpus: [],
- gpus: [],
- memories: [],
- storages: [],
- },
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/actions/topology/room.js b/opendc-web/opendc-web-ui/src/redux/actions/topology/room.js
deleted file mode 100644
index 14cc126c..00000000
--- a/opendc-web/opendc-web-ui/src/redux/actions/topology/room.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import { v4 as uuid } from 'uuid'
-import {
- DEFAULT_RACK_SLOT_CAPACITY,
- DEFAULT_RACK_POWER_CAPACITY,
-} from '../../../components/topologies/map/MapConstants'
-import { findTileWithPosition } from '../../../util/tile-calculations'
-
-export const ADD_ROOM = 'ADD_ROOM'
-export const EDIT_ROOM_NAME = 'EDIT_ROOM_NAME'
-export const DELETE_ROOM = 'DELETE_ROOM'
-export const START_RACK_CONSTRUCTION = 'START_RACK_CONSTRUCTION'
-export const STOP_RACK_CONSTRUCTION = 'STOP_RACK_CONSTRUCTION'
-export const ADD_RACK_TO_TILE = 'ADD_RACK_TO_TILE'
-
-export function addRoom(topologyId, room) {
- return {
- type: ADD_ROOM,
- room: {
- id: uuid(),
- topologyId,
- ...room,
- },
- }
-}
-
-export function editRoomName(roomId, name) {
- return {
- type: EDIT_ROOM_NAME,
- name,
- roomId,
- }
-}
-
-export function startRackConstruction() {
- return {
- type: START_RACK_CONSTRUCTION,
- }
-}
-
-export function stopRackConstruction() {
- return {
- type: STOP_RACK_CONSTRUCTION,
- }
-}
-
-export function addRackToTile(positionX, positionY) {
- return (dispatch, getState) => {
- const { topology, interactionLevel } = getState()
- const currentRoom = topology.rooms[interactionLevel.roomId]
- const tiles = currentRoom.tiles.map((tileId) => topology.tiles[tileId])
- const tile = findTileWithPosition(tiles, positionX, positionY)
-
- if (tile !== null) {
- dispatch({
- type: ADD_RACK_TO_TILE,
- tileId: tile.id,
- rack: {
- id: uuid(),
- name: 'Rack',
- capacity: DEFAULT_RACK_SLOT_CAPACITY,
- powerCapacityW: DEFAULT_RACK_POWER_CAPACITY,
- machines: [],
- },
- })
- }
- }
-}
-
-export function deleteRoom(roomId) {
- return {
- type: DELETE_ROOM,
- roomId,
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/index.js b/opendc-web/opendc-web-ui/src/redux/index.js
deleted file mode 100644
index 53cd9144..00000000
--- a/opendc-web/opendc-web-ui/src/redux/index.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import { useMemo } from 'react'
-import { applyMiddleware, compose, createStore } from 'redux'
-import { createLogger } from 'redux-logger'
-import createSagaMiddleware from 'redux-saga'
-import thunk from 'redux-thunk'
-import rootReducer from './reducers'
-import rootSaga from './sagas'
-import { createReduxEnhancer } from '@sentry/react'
-import { sentryDsn } from '../config'
-
-let store
-
-function initStore(initialState, ctx) {
- const sagaMiddleware = createSagaMiddleware({ context: ctx })
-
- const middlewares = [thunk, sagaMiddleware]
-
- if (process.env.NODE_ENV !== 'production') {
- middlewares.push(createLogger())
- }
-
- let middleware = applyMiddleware(...middlewares)
-
- if (sentryDsn) {
- middleware = compose(middleware, createReduxEnhancer())
- }
-
- const configuredStore = createStore(rootReducer, initialState, middleware)
- sagaMiddleware.run(rootSaga)
- store = configuredStore
-
- return configuredStore
-}
-
-export const initializeStore = (preloadedState, ctx) => {
- let _store = store ?? initStore(preloadedState, ctx)
-
- // After navigating to a page with an initial Redux state, merge that state
- // with the current state in the store, and create a new store
- if (preloadedState && store) {
- _store = initStore({
- ...store.getState(),
- ...preloadedState,
- })
- // Reset the current store
- store = undefined
- }
-
- // For SSG and SSR always create a new store
- if (typeof window === 'undefined') return _store
- // Create the store once in the client
- if (!store) store = _store
-
- return _store
-}
-
-export function useStore(initialState, ctx) {
- return useMemo(() => initializeStore(initialState, ctx), [initialState, ctx])
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/construction-mode.js b/opendc-web/opendc-web-ui/src/redux/reducers/construction-mode.js
deleted file mode 100644
index d0aac5ae..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/construction-mode.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { combineReducers } from 'redux'
-import { GO_DOWN_ONE_INTERACTION_LEVEL } from '../actions/interaction-level'
-import {
- CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED,
- FINISH_NEW_ROOM_CONSTRUCTION,
- FINISH_ROOM_EDIT,
- START_NEW_ROOM_CONSTRUCTION_SUCCEEDED,
- START_ROOM_EDIT,
-} from '../actions/topology/building'
-import { DELETE_ROOM, START_RACK_CONSTRUCTION, STOP_RACK_CONSTRUCTION } from '../actions/topology/room'
-
-export function currentRoomInConstruction(state = '-1', action) {
- switch (action.type) {
- case START_NEW_ROOM_CONSTRUCTION_SUCCEEDED:
- return action.roomId
- case START_ROOM_EDIT:
- return action.roomId
- case CANCEL_NEW_ROOM_CONSTRUCTION_SUCCEEDED:
- case FINISH_NEW_ROOM_CONSTRUCTION:
- case FINISH_ROOM_EDIT:
- case DELETE_ROOM:
- return '-1'
- default:
- return state
- }
-}
-
-export function inRackConstructionMode(state = false, action) {
- switch (action.type) {
- case START_RACK_CONSTRUCTION:
- return true
- case STOP_RACK_CONSTRUCTION:
- case GO_DOWN_ONE_INTERACTION_LEVEL:
- return false
- default:
- return state
- }
-}
-
-export const construction = combineReducers({
- currentRoomInConstruction,
- inRackConstructionMode,
-})
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/index.js b/opendc-web/opendc-web-ui/src/redux/reducers/index.js
deleted file mode 100644
index 7ffb1211..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import { combineReducers } from 'redux'
-import { construction } from './construction-mode'
-import { interactionLevel } from './interaction-level'
-import topology from './topology'
-
-const rootReducer = combineReducers({
- topology,
- construction,
- interactionLevel,
-})
-
-export default rootReducer
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/interaction-level.js b/opendc-web/opendc-web-ui/src/redux/reducers/interaction-level.js
deleted file mode 100644
index b30c68b9..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/interaction-level.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import {
- GO_DOWN_ONE_INTERACTION_LEVEL,
- GO_FROM_BUILDING_TO_ROOM,
- GO_FROM_RACK_TO_MACHINE,
- GO_FROM_ROOM_TO_RACK,
-} from '../actions/interaction-level'
-import { DELETE_MACHINE } from '../actions/topology/machine'
-import { DELETE_RACK } from '../actions/topology/rack'
-import { DELETE_ROOM } from '../actions/topology/room'
-
-export function interactionLevel(state = { mode: 'BUILDING' }, action) {
- switch (action.type) {
- case GO_FROM_BUILDING_TO_ROOM:
- return {
- mode: 'ROOM',
- roomId: action.roomId,
- }
- case GO_FROM_ROOM_TO_RACK:
- return {
- mode: 'RACK',
- roomId: state.roomId,
- tileId: action.tileId,
- }
- case GO_FROM_RACK_TO_MACHINE:
- return {
- mode: 'MACHINE',
- roomId: state.roomId,
- tileId: state.tileId,
- position: action.position,
- }
- case GO_DOWN_ONE_INTERACTION_LEVEL:
- if (state.mode === 'ROOM') {
- return {
- mode: 'BUILDING',
- }
- } else if (state.mode === 'RACK') {
- return {
- mode: 'ROOM',
- roomId: state.roomId,
- }
- } else if (state.mode === 'MACHINE') {
- return {
- mode: 'RACK',
- roomId: state.roomId,
- tileId: state.tileId,
- }
- } else {
- return state
- }
- case DELETE_MACHINE:
- return {
- mode: 'RACK',
- roomId: state.roomId,
- tileId: state.tileId,
- }
- case DELETE_RACK:
- return {
- mode: 'ROOM',
- roomId: state.roomId,
- }
- case DELETE_ROOM:
- return {
- mode: 'BUILDING',
- }
- default:
- return state
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/topology/index.js b/opendc-web/opendc-web-ui/src/redux/reducers/topology/index.js
deleted file mode 100644
index 2c849387..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/topology/index.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { CPU_UNITS, GPU_UNITS, MEMORY_UNITS, STORAGE_UNITS } from '../../../util/unit-specifications'
-import machine from './machine'
-import rack from './rack'
-import room from './room'
-import tile from './tile'
-import topology from './topology'
-
-function objects(state = {}, action) {
- return {
- cpus: CPU_UNITS,
- gpus: GPU_UNITS,
- memories: MEMORY_UNITS,
- storages: STORAGE_UNITS,
- machines: machine(state.machines, action, state),
- racks: rack(state.racks, action, state),
- tiles: tile(state.tiles, action),
- rooms: room(state.rooms, action, state),
- root: topology(state.root, action, state),
- }
-}
-
-export default objects
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/topology/machine.js b/opendc-web/opendc-web-ui/src/redux/reducers/topology/machine.js
deleted file mode 100644
index 1789257b..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/topology/machine.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import produce from 'immer'
-import { STORE_TOPOLOGY } from '../../actions/topology'
-import { DELETE_MACHINE, ADD_UNIT, DELETE_UNIT } from '../../actions/topology/machine'
-import { ADD_MACHINE, DELETE_RACK } from '../../actions/topology/rack'
-
-function machine(state = {}, action, { racks }) {
- switch (action.type) {
- case STORE_TOPOLOGY:
- return action.entities.machines || {}
- case ADD_MACHINE:
- return produce(state, (draft) => {
- const { machine } = action
- draft[machine.id] = machine
- })
- case DELETE_MACHINE:
- return produce(state, (draft) => {
- const { machineId } = action
- delete draft[machineId]
- })
- case ADD_UNIT:
- return produce(state, (draft) => {
- const { machineId, unitType, unitId } = action
- draft[machineId][unitType].push(unitId)
- })
- case DELETE_UNIT:
- return produce(state, (draft) => {
- const { machineId, unitType, unitId } = action
- const units = draft[machineId][unitType]
- const index = units.indexOf(unitId)
- units.splice(index, 1)
- })
- case DELETE_RACK:
- return produce(state, (draft) => {
- const { rackId } = action
- const rack = racks[rackId]
-
- for (const id of rack.machines) {
- const machine = draft[id]
- machine.rackId = undefined
- }
- })
- default:
- return state
- }
-}
-
-export default machine
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/topology/rack.js b/opendc-web/opendc-web-ui/src/redux/reducers/topology/rack.js
deleted file mode 100644
index ca79348a..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/topology/rack.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import produce from 'immer'
-import { STORE_TOPOLOGY } from '../../actions/topology'
-import { DELETE_MACHINE } from '../../actions/topology/machine'
-import { DELETE_RACK, EDIT_RACK_NAME, ADD_MACHINE } from '../../actions/topology/rack'
-import { ADD_RACK_TO_TILE } from '../../actions/topology/room'
-
-function rack(state = {}, action, { machines }) {
- switch (action.type) {
- case STORE_TOPOLOGY:
- return action.entities.racks || {}
- case ADD_RACK_TO_TILE:
- return produce(state, (draft) => {
- const { rack } = action
- draft[rack.id] = rack
- })
- case EDIT_RACK_NAME:
- return produce(state, (draft) => {
- const { rackId, name } = action
- draft[rackId].name = name
- })
- case DELETE_RACK:
- return produce(state, (draft) => {
- const { rackId } = action
- delete draft[rackId]
- })
- case ADD_MACHINE:
- return produce(state, (draft) => {
- const { machine } = action
- draft[machine.rackId].machines.push(machine.id)
- })
- case DELETE_MACHINE:
- return produce(state, (draft) => {
- const { machineId } = action
- const machine = machines[machineId]
- const rack = draft[machine.rackId]
- const index = rack.machines.indexOf(machineId)
- rack.machines.splice(index, 1)
- })
- default:
- return state
- }
-}
-
-export default rack
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/topology/room.js b/opendc-web/opendc-web-ui/src/redux/reducers/topology/room.js
deleted file mode 100644
index c05c8bfa..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/topology/room.js
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import produce from 'immer'
-import { STORE_TOPOLOGY } from '../../actions/topology'
-import { ADD_TILE, DELETE_TILE } from '../../actions/topology/building'
-import { DELETE_ROOM, EDIT_ROOM_NAME, ADD_ROOM } from '../../actions/topology/room'
-
-function room(state = {}, action, { tiles }) {
- switch (action.type) {
- case STORE_TOPOLOGY:
- return action.entities.rooms || {}
- case ADD_ROOM:
- return produce(state, (draft) => {
- const { room } = action
- draft[room.id] = room
- })
- case DELETE_ROOM:
- return produce(state, (draft) => {
- const { roomId } = action
- delete draft[roomId]
- })
- case EDIT_ROOM_NAME:
- return produce(state, (draft) => {
- const { roomId, name } = action
- draft[roomId].name = name
- })
- case ADD_TILE:
- return produce(state, (draft) => {
- const { tile } = action
- draft[tile.roomId].tiles.push(tile.id)
- })
- case DELETE_TILE:
- return produce(state, (draft) => {
- const { tileId } = action
- const tile = tiles[tileId]
- const room = draft[tile.roomId]
- const index = room.tiles.indexOf(tileId)
- room.tiles.splice(index, 1)
- })
- default:
- return state
- }
-}
-
-export default room
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/topology/tile.js b/opendc-web/opendc-web-ui/src/redux/reducers/topology/tile.js
deleted file mode 100644
index 24c0e20c..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/topology/tile.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import produce from 'immer'
-import { STORE_TOPOLOGY } from '../../actions/topology'
-import { ADD_TILE, DELETE_TILE } from '../../actions/topology/building'
-import { DELETE_RACK } from '../../actions/topology/rack'
-import { ADD_RACK_TO_TILE } from '../../actions/topology/room'
-
-function tile(state = {}, action) {
- switch (action.type) {
- case STORE_TOPOLOGY:
- return action.entities.tiles || {}
- case ADD_TILE:
- return produce(state, (draft) => {
- const { tile } = action
- draft[tile.id] = tile
- })
- case DELETE_TILE:
- return produce(state, (draft) => {
- const { tileId } = action
- delete draft[tileId]
- })
- case ADD_RACK_TO_TILE:
- return produce(state, (draft) => {
- const { rack, tileId } = action
- draft[tileId].rack = rack.id
- })
- case DELETE_RACK:
- return produce(state, (draft) => {
- const { tileId } = action
- draft[tileId].rack = undefined
- })
- default:
- return state
- }
-}
-
-export default tile
diff --git a/opendc-web/opendc-web-ui/src/redux/reducers/topology/topology.js b/opendc-web/opendc-web-ui/src/redux/reducers/topology/topology.js
deleted file mode 100644
index dff0a69e..00000000
--- a/opendc-web/opendc-web-ui/src/redux/reducers/topology/topology.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import produce from 'immer'
-import { STORE_TOPOLOGY } from '../../actions/topology'
-import { ADD_ROOM, DELETE_ROOM } from '../../actions/topology/room'
-
-function topology(state = undefined, action) {
- switch (action.type) {
- case STORE_TOPOLOGY:
- return action.topology
- case ADD_ROOM:
- return produce(state, (draft) => {
- const { room } = action
- draft.rooms.push(room.id)
- })
- case DELETE_ROOM:
- return produce(state, (draft) => {
- const { roomId } = action
- const index = draft.rooms.indexOf(roomId)
- draft.rooms.splice(index, 1)
- })
- default:
- return state
- }
-}
-
-export default topology
diff --git a/opendc-web/opendc-web-ui/src/redux/sagas/index.js b/opendc-web/opendc-web-ui/src/redux/sagas/index.js
deleted file mode 100644
index 0fabdb6d..00000000
--- a/opendc-web/opendc-web-ui/src/redux/sagas/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import { fork } from 'redux-saga/effects'
-import { watchServer, updateServer } from './topology'
-
-export default function* rootSaga() {
- yield fork(watchServer)
- yield fork(updateServer)
-}
diff --git a/opendc-web/opendc-web-ui/src/redux/sagas/topology.js b/opendc-web/opendc-web-ui/src/redux/sagas/topology.js
deleted file mode 100644
index 15147bcf..00000000
--- a/opendc-web/opendc-web-ui/src/redux/sagas/topology.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import { QueryObserver, MutationObserver } from 'react-query'
-import { normalize, denormalize } from 'normalizr'
-import { select, put, take, race, getContext, call } from 'redux-saga/effects'
-import { eventChannel } from 'redux-saga'
-import { Topology } from '../../util/topology-schema'
-import { storeTopology, OPEN_TOPOLOGY } from '../actions/topology'
-
-/**
- * Update the topology on the server.
- */
-export function* updateServer() {
- const queryClient = yield getContext('queryClient')
- const mutationObserver = new MutationObserver(queryClient, { mutationKey: 'updateTopology' })
-
- while (true) {
- yield take(
- (action) =>
- action.type.startsWith('EDIT') || action.type.startsWith('ADD') || action.type.startsWith('DELETE')
- )
- const topology = yield select((state) => state.topology)
-
- if (!topology.root) {
- continue
- }
-
- const denormalizedTopology = denormalize(topology.root, Topology, topology)
- yield call([mutationObserver, mutationObserver.mutate], denormalizedTopology)
- }
-}
-
-/**
- * Watch the topology on the server for changes.
- */
-export function* watchServer() {
- let { projectId, id } = yield take(OPEN_TOPOLOGY)
- while (true) {
- const channel = yield queryObserver(projectId, id)
-
- while (true) {
- const [action, response] = yield race([take(OPEN_TOPOLOGY), take(channel)])
-
- if (action) {
- projectId = action.projectId
- id = action.id
- break
- }
-
- const { isFetched, data } = response
- // Only update the topology on the client-side when a new topology was fetched
- if (isFetched) {
- const { result: topologyId, entities } = normalize(data, Topology)
- yield put(storeTopology(entities.topologies[topologyId], entities))
- }
- }
- }
-}
-
-/**
- * Observe changes for the topology with the specified identifier.
- */
-function* queryObserver(projectId, id) {
- const queryClient = yield getContext('queryClient')
- const observer = new QueryObserver(queryClient, { queryKey: ['topologies', projectId, id] })
-
- return eventChannel((emitter) => {
- const unsubscribe = observer.subscribe((result) => {
- emitter(result)
- })
-
- // Update result to make sure we did not miss any query updates
- // between creating the observer and subscribing to it.
- observer.updateResult()
-
- return unsubscribe
- })
-}
diff --git a/opendc-web/opendc-web-ui/src/shapes.js b/opendc-web/opendc-web-ui/src/shapes.js
deleted file mode 100644
index 50b82361..00000000
--- a/opendc-web/opendc-web-ui/src/shapes.js
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import PropTypes from 'prop-types'
-
-export const ProjectRole = PropTypes.oneOf(['VIEWER', 'EDITOR', 'OWNER'])
-
-export const Project = PropTypes.shape({
- id: PropTypes.number.isRequired,
- name: PropTypes.string.isRequired,
- createdAt: PropTypes.string.isRequired,
- updatedAt: PropTypes.string.isRequired,
- role: ProjectRole,
-})
-
-export const ProcessingUnit = PropTypes.shape({
- id: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- clockRateMhz: PropTypes.number.isRequired,
- numberOfCores: PropTypes.number.isRequired,
- energyConsumptionW: PropTypes.number.isRequired,
-})
-
-export const StorageUnit = PropTypes.shape({
- id: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- speedMbPerS: PropTypes.number.isRequired,
- sizeMb: PropTypes.number.isRequired,
- energyConsumptionW: PropTypes.number.isRequired,
-})
-
-export const Machine = PropTypes.shape({
- id: PropTypes.string.isRequired,
- position: PropTypes.number.isRequired,
- cpus: PropTypes.arrayOf(PropTypes.oneOfType([ProcessingUnit, PropTypes.string])),
- gpus: PropTypes.arrayOf(PropTypes.oneOfType([ProcessingUnit, PropTypes.string])),
- memories: PropTypes.arrayOf(PropTypes.oneOfType([StorageUnit, PropTypes.string])),
- storages: PropTypes.arrayOf(PropTypes.oneOfType([StorageUnit, PropTypes.string])),
-})
-
-export const Rack = PropTypes.shape({
- id: PropTypes.string.isRequired,
- capacity: PropTypes.number.isRequired,
- powerCapacityW: PropTypes.number.isRequired,
- machines: PropTypes.arrayOf(PropTypes.oneOfType([Machine, PropTypes.string])),
-})
-
-export const Tile = PropTypes.shape({
- id: PropTypes.string.isRequired,
- positionX: PropTypes.number.isRequired,
- positionY: PropTypes.number.isRequired,
- rack: PropTypes.oneOfType([Rack, PropTypes.string]),
-})
-
-export const Room = PropTypes.shape({
- id: PropTypes.string.isRequired,
- name: PropTypes.string.isRequired,
- tiles: PropTypes.arrayOf(PropTypes.oneOfType([Tile, PropTypes.string])),
-})
-
-export const Topology = PropTypes.shape({
- id: PropTypes.number.isRequired,
- number: PropTypes.number.isRequired,
- project: Project.isRequired,
- name: PropTypes.string.isRequired,
- rooms: PropTypes.arrayOf(PropTypes.oneOfType([Room, PropTypes.string])),
-})
-
-export const Phenomena = PropTypes.shape({
- failures: PropTypes.bool.isRequired,
- interference: PropTypes.bool.isRequired,
-})
-
-export const Scheduler = PropTypes.shape({
- name: PropTypes.string.isRequired,
-})
-
-export const Trace = PropTypes.shape({
- id: PropTypes.number.isRequired,
- name: PropTypes.string.isRequired,
- type: PropTypes.string.isRequired,
-})
-
-export const Workload = PropTypes.shape({
- trace: Trace.isRequired,
- samplingFraction: PropTypes.number.isRequired,
-})
-
-export const Targets = PropTypes.shape({
- repeats: PropTypes.number.isRequired,
- metrics: PropTypes.arrayOf(PropTypes.string).isRequired,
-})
-
-export const TopologySummary = PropTypes.shape({
- id: PropTypes.number.isRequired,
- number: PropTypes.number.isRequired,
- project: Project.isRequired,
- name: PropTypes.string.isRequired,
-})
-
-export const PortfolioSummary = PropTypes.shape({
- id: PropTypes.number.isRequired,
- number: PropTypes.number.isRequired,
- project: Project.isRequired,
- name: PropTypes.string.isRequired,
- targets: PropTypes.shape({
- repeats: PropTypes.number.isRequired,
- metrics: PropTypes.arrayOf(PropTypes.string).isRequired,
- }).isRequired,
-})
-
-export const ScenarioSummary = PropTypes.shape({
- id: PropTypes.number.isRequired,
- number: PropTypes.number.isRequired,
- name: PropTypes.string.isRequired,
- workload: Workload.isRequired,
- topology: TopologySummary.isRequired,
- phenomena: Phenomena.isRequired,
- schedulerName: PropTypes.string.isRequired,
- results: PropTypes.object,
-})
-
-export const JobState = PropTypes.oneOf(['PENDING', 'CLAIMED', 'RUNNING', 'FAILED', 'FINISHED'])
-
-export const Job = PropTypes.shape({
- id: PropTypes.number.isRequired,
- state: JobState.isRequired,
- createdAt: PropTypes.string.isRequired,
- updatedAt: PropTypes.string.isRequired,
- results: PropTypes.object,
-})
-
-export const Scenario = PropTypes.shape({
- id: PropTypes.number.isRequired,
- number: PropTypes.number.isRequired,
- project: Project.isRequired,
- portfolio: PortfolioSummary.isRequired,
- name: PropTypes.string.isRequired,
- workload: Workload.isRequired,
- topology: TopologySummary.isRequired,
- phenomena: Phenomena.isRequired,
- schedulerName: PropTypes.string.isRequired,
- jobs: PropTypes.arrayOf(Job).isRequired,
-})
-
-export const Portfolio = PropTypes.shape({
- id: PropTypes.number.isRequired,
- number: PropTypes.number.isRequired,
- name: PropTypes.string.isRequired,
- project: Project.isRequired,
- targets: Targets.isRequired,
- scenarios: PropTypes.arrayOf(ScenarioSummary).isRequired,
-})
-
-export const WallSegment = PropTypes.shape({
- startPosX: PropTypes.number.isRequired,
- startPosY: PropTypes.number.isRequired,
- isHorizontal: PropTypes.bool.isRequired,
- length: PropTypes.number.isRequired,
-})
-
-export const InteractionLevel = PropTypes.shape({
- mode: PropTypes.string.isRequired,
- roomId: PropTypes.string,
- rackId: PropTypes.string,
-})
-
-export const Status = PropTypes.oneOf(['idle', 'loading', 'error', 'success'])
diff --git a/opendc-web/opendc-web-ui/src/style/index.css b/opendc-web/opendc-web-ui/src/style/index.css
deleted file mode 100644
index 7b7103a4..00000000
--- a/opendc-web/opendc-web-ui/src/style/index.css
+++ /dev/null
@@ -1,28 +0,0 @@
-/*!
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-body,
-#__next {
- height: 100%;
-
- background: #eee;
-}
diff --git a/opendc-web/opendc-web-ui/src/util/authorizations.js b/opendc-web/opendc-web-ui/src/util/authorizations.js
deleted file mode 100644
index 6cb08ba8..00000000
--- a/opendc-web/opendc-web-ui/src/util/authorizations.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import HomeIcon from '@patternfly/react-icons/dist/js/icons/home-icon'
-import EditIcon from '@patternfly/react-icons/dist/js/icons/edit-icon'
-import EyeIcon from '@patternfly/react-icons/dist/js/icons/eye-icon'
-
-export const AUTH_ICON_MAP = {
- OWNER: HomeIcon,
- EDITOR: EditIcon,
- VIEWER: EyeIcon,
-}
-
-export const AUTH_NAME_MAP = {
- OWNER: 'Owner',
- EDITOR: 'Editor',
- VIEWER: 'Viewer',
-}
-
-export const AUTH_DESCRIPTION_MAP = {
- OWNER: 'You own this project',
- EDITOR: 'You can edit this project',
- VIEWER: 'You can view this project',
-}
diff --git a/opendc-web/opendc-web-ui/src/util/available-metrics.js b/opendc-web/opendc-web-ui/src/util/available-metrics.js
deleted file mode 100644
index fda6cd4d..00000000
--- a/opendc-web/opendc-web-ui/src/util/available-metrics.js
+++ /dev/null
@@ -1,101 +0,0 @@
-export const METRIC_GROUPS = {
- 'Host Metrics': [
- 'total_overcommitted_burst',
- 'total_power_draw',
- 'total_failure_vm_slices',
- 'total_granted_burst',
- 'total_interfered_burst',
- 'total_requested_burst',
- 'mean_cpu_usage',
- 'mean_cpu_demand',
- 'mean_num_deployed_images',
- 'max_num_deployed_images',
- ],
- 'Compute Service Metrics': ['total_vms_submitted', 'total_vms_queued', 'total_vms_finished', 'total_vms_failed'],
-}
-
-export const AVAILABLE_METRICS = [
- 'mean_cpu_usage',
- 'mean_cpu_demand',
- 'total_requested_burst',
- 'total_granted_burst',
- 'total_overcommitted_burst',
- 'total_interfered_burst',
- 'total_power_draw',
- 'total_failure_vm_slices',
- 'mean_num_deployed_images',
- 'max_num_deployed_images',
- 'total_vms_submitted',
- 'total_vms_queued',
- 'total_vms_finished',
- 'total_vms_failed',
-]
-
-export const METRIC_NAMES_SHORT = {
- total_overcommitted_burst: 'Overcomm. CPU Cycles',
- total_granted_burst: 'Granted CPU Cycles',
- total_requested_burst: 'Requested CPU Cycles',
- total_interfered_burst: 'Interfered CPU Cycles',
- total_power_draw: 'Total Power Consumption',
- mean_cpu_usage: 'Mean Host CPU Usage',
- mean_cpu_demand: 'Mean Host CPU Demand',
- mean_num_deployed_images: 'Mean Num. Deployed Images Per Host',
- max_num_deployed_images: 'Max. Num. Deployed Images Per Host',
- total_failure_vm_slices: 'Total Num. Failed VM Slices',
- total_vms_submitted: 'VMs Submitted',
- total_vms_queued: 'VMs Queued',
- total_vms_finished: 'VMs Finished',
- total_vms_failed: 'VMs Failed',
-}
-
-export const METRIC_NAMES = {
- total_overcommitted_burst: 'Overcommitted CPU Cycles',
- total_granted_burst: 'Granted CPU Cycles',
- total_requested_burst: 'Requested CPU Cycles',
- total_interfered_burst: 'Interfered CPU Cycles',
- total_power_draw: 'Total Power Consumption',
- mean_cpu_usage: 'Mean Host CPU Usage',
- mean_cpu_demand: 'Mean Host CPU Demand',
- mean_num_deployed_images: 'Mean Number of Deployed Images Per Host',
- max_num_deployed_images: 'Maximum Number Deployed Images Per Host',
- total_failure_vm_slices: 'Failed VM Slices',
- total_vms_submitted: 'VMs Submitted',
- total_vms_queued: 'VMs Queued',
- total_vms_finished: 'VMs Finished',
- total_vms_failed: 'VMs Failed',
-}
-
-export const METRIC_UNITS = {
- total_overcommitted_burst: 'MFLOP',
- total_granted_burst: 'MFLOP',
- total_requested_burst: 'MFLOP',
- total_interfered_burst: 'MFLOP',
- total_power_draw: 'Wh',
- mean_cpu_usage: 'MHz',
- mean_cpu_demand: 'MHz',
- mean_num_deployed_images: 'VMs',
- max_num_deployed_images: 'VMs',
- total_failure_vm_slices: 'VM Slices',
- total_vms_submitted: 'VMs',
- total_vms_queued: 'VMs',
- total_vms_finished: 'VMs',
- total_vms_failed: 'VMs',
-}
-
-export const METRIC_DESCRIPTIONS = {
- total_overcommitted_burst:
- 'The total CPU clock cycles lost due to overcommitting of resources. This metric is an indicator for resource overload.',
- total_requested_burst: 'The total CPU clock cycles that were requested by all virtual machines.',
- total_granted_burst: 'The total CPU clock cycles executed by the hosts.',
- total_interfered_burst: 'The total CPU clock cycles lost due to resource interference between virtual machines.',
- total_power_draw: 'The average power usage in watts.',
- mean_cpu_usage: 'The average amount of CPU clock cycles consumed by all virtual machines on a host.',
- mean_cpu_demand: 'The average amount of CPU clock cycles requested by all powered on virtual machines on a host.',
- mean_num_deployed_images: 'The average number of virtual machines deployed on a host.',
- max_num_deployed_images: 'The maximum number of virtual machines deployed at any time.',
- total_failure_vm_slices: 'The total amount of CPU clock cycles lost due to failure.',
- total_vms_submitted: 'The number of virtual machines scheduled by the compute service.',
- total_vms_queued: 'The number of virtual machines still waiting to be scheduled by the compute service.',
- total_vms_finished: 'The number of virtual machines that completed.',
- total_vms_failed: 'The number of virtual machines that could not be scheduled.',
-}
diff --git a/opendc-web/opendc-web-ui/src/util/colors.js b/opendc-web/opendc-web-ui/src/util/colors.js
deleted file mode 100644
index 34468503..00000000
--- a/opendc-web/opendc-web-ui/src/util/colors.js
+++ /dev/null
@@ -1,29 +0,0 @@
-export const GRID_COLOR = 'rgba(0, 0, 0, 0.5)'
-export const BACKDROP_COLOR = 'rgba(255, 255, 255, 1)'
-export const WALL_COLOR = 'rgba(0, 0, 0, 1)'
-
-export const ROOM_DEFAULT_COLOR = 'rgba(150, 150, 150, 1)'
-export const ROOM_IN_CONSTRUCTION_COLOR = 'rgba(51, 153, 255, 1)'
-export const ROOM_HOVER_VALID_COLOR = 'rgba(51, 153, 255, 1)'
-export const ROOM_HOVER_INVALID_COLOR = 'rgba(255, 102, 0, 1)'
-export const ROOM_NAME_COLOR = 'rgba(245, 245, 245, 1)'
-export const ROOM_TYPE_COLOR = 'rgba(245, 245, 245, 1)'
-
-export const TILE_PLUS_COLOR = 'rgba(0, 0, 0, 1)'
-
-export const OBJECT_BORDER_COLOR = 'rgba(0, 0, 0, 1)'
-
-export const RACK_BACKGROUND_COLOR = 'rgba(170, 170, 170, 1)'
-export const RACK_SPACE_BAR_BACKGROUND_COLOR = 'rgba(222, 235, 247, 0.6)'
-export const RACK_SPACE_BAR_FILL_COLOR = 'rgba(91, 155, 213, 0.7)'
-export const RACK_ENERGY_BAR_BACKGROUND_COLOR = 'rgba(255, 242, 204, 0.6)'
-export const RACK_ENERGY_BAR_FILL_COLOR = 'rgba(244, 215, 0, 0.7)'
-export const COOLING_ITEM_BACKGROUND_COLOR = 'rgba(40, 50, 230, 1)'
-export const PSU_BACKGROUND_COLOR = 'rgba(230, 50, 60, 1)'
-
-export const GRAYED_OUT_AREA_COLOR = 'rgba(0, 0, 0, 0.6)'
-
-export const SIM_LOW_COLOR = 'rgba(197, 224, 180, 1)'
-export const SIM_MID_LOW_COLOR = 'rgba(255, 230, 153, 1)'
-export const SIM_MID_HIGH_COLOR = 'rgba(248, 203, 173, 1)'
-export const SIM_HIGH_COLOR = 'rgba(249, 165, 165, 1)'
diff --git a/opendc-web/opendc-web-ui/src/util/date-time.js b/opendc-web/opendc-web-ui/src/util/date-time.js
deleted file mode 100644
index 7e2f6623..00000000
--- a/opendc-web/opendc-web-ui/src/util/date-time.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Parses and formats the given date-time string representation.
- *
- * The format assumed is "YYYY-MM-DDTHH:MM:SS".
- *
- * @param dateTimeString A string expressing a date and a time, in the above mentioned format.
- * @returns {string} A human-friendly string version of that date and time.
- */
-export function parseAndFormatDateTime(dateTimeString) {
- return formatDateTime(new Date(dateTimeString))
-}
-
-/**
- * Serializes the given date and time value to a human-friendly string.
- *
- * @param dateTime An object representation of a date and time.
- * @returns {string} A human-friendly string version of that date and time.
- */
-export function formatDateTime(dateTime) {
- let date
- const currentDate = new Date()
-
- date =
- addPaddingToTwo(dateTime.getDay()) +
- '/' +
- addPaddingToTwo(dateTime.getMonth()) +
- '/' +
- addPaddingToTwo(dateTime.getFullYear())
-
- if (dateTime.getFullYear() === currentDate.getFullYear() && dateTime.getMonth() === currentDate.getMonth()) {
- if (dateTime.getDate() === currentDate.getDate()) {
- date = 'Today'
- } else if (dateTime.getDate() === currentDate.getDate() - 1) {
- date = 'Yesterday'
- }
- }
-
- return date + ', ' + addPaddingToTwo(dateTime.getHours()) + ':' + addPaddingToTwo(dateTime.getMinutes())
-}
-
-/**
- * Formats the given number of seconds/ticks to a formatted time representation.
- *
- * @param seconds The number of seconds.
- * @returns {string} A string representation of that amount of second, in the from of HH:MM:SS.
- */
-export function convertSecondsToFormattedTime(seconds) {
- if (seconds <= 0) {
- return '0s'
- }
-
- let hour = Math.floor(seconds / 3600)
- let minute = Math.floor(seconds / 60) % 60
- let second = seconds % 60
-
- hour = isNaN(hour) ? 0 : hour
- minute = isNaN(minute) ? 0 : minute
- second = isNaN(second) ? 0 : second
-
- if (hour === 0 && minute === 0) {
- return second + 's'
- } else if (hour === 0) {
- return minute + 'm' + addPaddingToTwo(second) + 's'
- } else {
- return hour + 'h' + addPaddingToTwo(minute) + 'm' + addPaddingToTwo(second) + 's'
- }
-}
-
-/**
- * Pads the given integer to have at least two digits.
- *
- * @param integer An integer to be padded.
- * @returns {string} A string containing the padded integer.
- */
-function addPaddingToTwo(integer) {
- if (integer < 10) {
- return '0' + integer.toString()
- } else {
- return integer.toString()
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/util/date-time.test.js b/opendc-web/opendc-web-ui/src/util/date-time.test.js
deleted file mode 100644
index 431e39f7..00000000
--- a/opendc-web/opendc-web-ui/src/util/date-time.test.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { convertSecondsToFormattedTime } from './date-time'
-
-describe('tick formatting', () => {
- it("returns '0s' for numbers <= 0", () => {
- expect(convertSecondsToFormattedTime(-1)).toEqual('0s')
- expect(convertSecondsToFormattedTime(0)).toEqual('0s')
- })
- it('returns only seconds for values under a minute', () => {
- expect(convertSecondsToFormattedTime(1)).toEqual('1s')
- expect(convertSecondsToFormattedTime(59)).toEqual('59s')
- })
- it('returns seconds and minutes for values under an hour', () => {
- expect(convertSecondsToFormattedTime(60)).toEqual('1m00s')
- expect(convertSecondsToFormattedTime(61)).toEqual('1m01s')
- expect(convertSecondsToFormattedTime(3599)).toEqual('59m59s')
- })
- it('returns full time for values over an hour', () => {
- expect(convertSecondsToFormattedTime(3600)).toEqual('1h00m00s')
- expect(convertSecondsToFormattedTime(3601)).toEqual('1h00m01s')
- })
-})
diff --git a/opendc-web/opendc-web-ui/src/util/effect-ref.js b/opendc-web/opendc-web-ui/src/util/effect-ref.js
deleted file mode 100644
index 78528585..00000000
--- a/opendc-web/opendc-web-ui/src/util/effect-ref.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { useCallback, useRef } from 'react'
-
-const noop = () => {}
-
-/**
- * A hook that will invoke the specified callback when the reference returned by this function is initialized.
- * The callback can return an optional clean-up function.
- */
-export function useEffectRef(callback, deps = []) {
- const disposeRef = useRef(noop)
- return useCallback((element) => {
- disposeRef.current()
- disposeRef.current = noop
-
- if (element) {
- disposeRef.current = callback(element) || noop
- }
- }, deps) // eslint-disable-line react-hooks/exhaustive-deps
-}
diff --git a/opendc-web/opendc-web-ui/src/util/tile-calculations.js b/opendc-web/opendc-web-ui/src/util/tile-calculations.js
deleted file mode 100644
index 374ca48c..00000000
--- a/opendc-web/opendc-web-ui/src/util/tile-calculations.js
+++ /dev/null
@@ -1,255 +0,0 @@
-export function deriveWallLocations(tiles) {
- const { verticalWalls, horizontalWalls } = getWallSegments(tiles)
- return mergeWallSegments(verticalWalls, horizontalWalls)
-}
-
-function getWallSegments(tiles) {
- const verticalWalls = {}
- const horizontalWalls = {}
-
- tiles.forEach((tile) => {
- const x = tile.positionX,
- y = tile.positionY
-
- for (let dX = -1; dX <= 1; dX++) {
- for (let dY = -1; dY <= 1; dY++) {
- if (Math.abs(dX) === Math.abs(dY)) {
- continue
- }
-
- let doInsert = true
- for (const tile of tiles) {
- if (tile.positionX === x + dX && tile.positionY === y + dY) {
- doInsert = false
- break
- }
- }
- if (!doInsert) {
- continue
- }
-
- if (dX === -1) {
- if (verticalWalls[x] === undefined) {
- verticalWalls[x] = []
- }
- if (verticalWalls[x].indexOf(y) === -1) {
- verticalWalls[x].push(y)
- }
- } else if (dX === 1) {
- if (verticalWalls[x + 1] === undefined) {
- verticalWalls[x + 1] = []
- }
- if (verticalWalls[x + 1].indexOf(y) === -1) {
- verticalWalls[x + 1].push(y)
- }
- } else if (dY === -1) {
- if (horizontalWalls[y] === undefined) {
- horizontalWalls[y] = []
- }
- if (horizontalWalls[y].indexOf(x) === -1) {
- horizontalWalls[y].push(x)
- }
- } else if (dY === 1) {
- if (horizontalWalls[y + 1] === undefined) {
- horizontalWalls[y + 1] = []
- }
- if (horizontalWalls[y + 1].indexOf(x) === -1) {
- horizontalWalls[y + 1].push(x)
- }
- }
- }
- }
- })
-
- return { verticalWalls, horizontalWalls }
-}
-
-function mergeWallSegments(vertical, horizontal) {
- const result = []
- const walls = [vertical, horizontal]
-
- for (let i = 0; i < 2; i++) {
- const wallList = walls[i]
- for (let a in wallList) {
- a = parseInt(a, 10)
-
- wallList[a].sort((a, b) => {
- return a - b
- })
-
- let startPos = wallList[a][0]
- const isHorizontal = i === 1
-
- if (wallList[a].length === 1) {
- const startPosX = isHorizontal ? startPos : a
- const startPosY = isHorizontal ? a : startPos
- result.push({
- startPosX,
- startPosY,
- isHorizontal,
- length: 1,
- })
- } else {
- let consecutiveCount = 1
- for (let b = 0; b < wallList[a].length - 1; b++) {
- if (b + 1 === wallList[a].length - 1) {
- if (wallList[a][b + 1] - wallList[a][b] > 1) {
- const startPosX = isHorizontal ? startPos : a
- const startPosY = isHorizontal ? a : startPos
- result.push({
- startPosX,
- startPosY,
- isHorizontal,
- length: consecutiveCount,
- })
- consecutiveCount = 0
- startPos = wallList[a][b + 1]
- }
- const startPosX = isHorizontal ? startPos : a
- const startPosY = isHorizontal ? a : startPos
- result.push({
- startPosX,
- startPosY,
- isHorizontal,
- length: consecutiveCount + 1,
- })
- break
- } else if (wallList[a][b + 1] - wallList[a][b] > 1) {
- const startPosX = isHorizontal ? startPos : a
- const startPosY = isHorizontal ? a : startPos
- result.push({
- startPosX,
- startPosY,
- isHorizontal,
- length: consecutiveCount,
- })
- startPos = wallList[a][b + 1]
- consecutiveCount = 0
- }
- consecutiveCount++
- }
- }
- }
- }
-
- return result
-}
-
-export function deriveValidNextTilePositions(rooms, selectedTiles) {
- const result = [],
- newPosition = { x: 0, y: 0 }
- let isSurroundingTile
-
- selectedTiles.forEach((tile) => {
- const x = tile.positionX
- const y = tile.positionY
- result.push({ x, y })
-
- for (let dX = -1; dX <= 1; dX++) {
- for (let dY = -1; dY <= 1; dY++) {
- if (Math.abs(dX) === Math.abs(dY)) {
- continue
- }
-
- newPosition.x = x + dX
- newPosition.y = y + dY
-
- isSurroundingTile = true
- for (let index in selectedTiles) {
- if (
- selectedTiles[index].positionX === newPosition.x &&
- selectedTiles[index].positionY === newPosition.y
- ) {
- isSurroundingTile = false
- break
- }
- }
-
- if (isSurroundingTile && findPositionInRooms(rooms, newPosition.x, newPosition.y) === -1) {
- result.push({ x: newPosition.x, y: newPosition.y })
- }
- }
- }
- })
-
- return result
-}
-
-export function findPositionInPositions(positions, positionX, positionY) {
- for (let i = 0; i < positions.length; i++) {
- const position = positions[i]
- if (positionX === position.x && positionY === position.y) {
- return i
- }
- }
-
- return -1
-}
-
-export function findPositionInRooms(rooms, positionX, positionY) {
- for (let i = 0; i < rooms.length; i++) {
- const room = rooms[i]
- if (findPositionInTiles(room.tiles, positionX, positionY) !== -1) {
- return i
- }
- }
-
- return -1
-}
-
-function findPositionInTiles(tiles, positionX, positionY) {
- let index = -1
-
- for (let i = 0; i < tiles.length; i++) {
- const tile = tiles[i]
- if (positionX === tile.positionX && positionY === tile.positionY) {
- index = i
- break
- }
- }
-
- return index
-}
-
-export function findTileWithPosition(tiles, positionX, positionY) {
- for (let i = 0; i < tiles.length; i++) {
- if (tiles[i].positionX === positionX && tiles[i].positionY === positionY) {
- return tiles[i]
- }
- }
-
- return null
-}
-
-export function calculateRoomListBounds(rooms) {
- const min = { x: Number.MAX_VALUE, y: Number.MAX_VALUE }
- const max = { x: -1, y: -1 }
-
- rooms.forEach((room) => {
- room.tiles.forEach((tile) => {
- if (tile.positionX < min.x) {
- min.x = tile.positionX
- }
- if (tile.positionY < min.y) {
- min.y = tile.positionY
- }
-
- if (tile.positionX > max.x) {
- max.x = tile.positionX
- }
- if (tile.positionY > max.y) {
- max.y = tile.positionY
- }
- })
- })
-
- max.x++
- max.y++
-
- const center = {
- x: min.x + (max.x - min.x) / 2.0,
- y: min.y + (max.y - min.y) / 2.0,
- }
-
- return { min, center, max }
-}
diff --git a/opendc-web/opendc-web-ui/src/util/topology-schema.js b/opendc-web/opendc-web-ui/src/util/topology-schema.js
deleted file mode 100644
index ff672dd6..00000000
--- a/opendc-web/opendc-web-ui/src/util/topology-schema.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-import { schema } from 'normalizr'
-
-const Cpu = new schema.Entity('cpus', {}, { idAttribute: 'id' })
-const Gpu = new schema.Entity('gpus', {}, { idAttribute: 'id' })
-const Memory = new schema.Entity('memories', {}, { idAttribute: 'id' })
-const Storage = new schema.Entity('storages', {}, { idAttribute: 'id' })
-
-export const Machine = new schema.Entity(
- 'machines',
- {
- cpus: [Cpu],
- gpus: [Gpu],
- memories: [Memory],
- storages: [Storage],
- },
- { idAttribute: 'id' }
-)
-
-export const Rack = new schema.Entity('racks', { machines: [Machine] }, { idAttribute: 'id' })
-
-export const Tile = new schema.Entity('tiles', { rack: Rack }, { idAttribute: 'id' })
-
-export const Room = new schema.Entity('rooms', { tiles: [Tile] }, { idAttribute: 'id' })
-
-export const Topology = new schema.Entity('topologies', { rooms: [Room] }, { idAttribute: 'id' })
diff --git a/opendc-web/opendc-web-ui/src/util/unit-specifications.js b/opendc-web/opendc-web-ui/src/util/unit-specifications.js
deleted file mode 100644
index 3e3671cd..00000000
--- a/opendc-web/opendc-web-ui/src/util/unit-specifications.js
+++ /dev/null
@@ -1,102 +0,0 @@
-export const CPU_UNITS = {
- 'cpu-1': {
- id: 'cpu-1',
- name: 'Intel i7 v6 6700k',
- clockRateMhz: 4100,
- numberOfCores: 4,
- energyConsumptionW: 70,
- },
- 'cpu-2': {
- id: 'cpu-2',
- name: 'Intel i5 v6 6700k',
- clockRateMhz: 3500,
- numberOfCores: 2,
- energyConsumptionW: 50,
- },
- 'cpu-3': {
- id: 'cpu-3',
- name: 'Intel® Xeon® E-2224G',
- clockRateMhz: 3500,
- numberOfCores: 4,
- energyConsumptionW: 71,
- },
- 'cpu-4': {
- id: 'cpu-4',
- name: 'Intel® Xeon® E-2244G',
- clockRateMhz: 3800,
- numberOfCores: 8,
- energyConsumptionW: 71,
- },
- 'cpu-5': {
- id: 'cpu-5',
- name: 'Intel® Xeon® E-2246G',
- clockRateMhz: 3600,
- numberOfCores: 12,
- energyConsumptionW: 80,
- },
-}
-
-export const GPU_UNITS = {
- 'gpu-1': {
- id: 'gpu-1',
- name: 'NVIDIA GTX 4 1080',
- clockRateMhz: 1200,
- numberOfCores: 200,
- energyConsumptionW: 250,
- },
- 'gpu-2': {
- id: 'gpu-2',
- name: 'NVIDIA Tesla V100',
- clockRateMhz: 1200,
- numberOfCores: 5120,
- energyConsumptionW: 250,
- },
-}
-
-export const MEMORY_UNITS = {
- 'memory-1': {
- id: 'memory-1',
- name: 'Samsung PC DRAM K4A4G045WD',
- speedMbPerS: 16000,
- sizeMb: 4000,
- energyConsumptionW: 10,
- },
- 'memory-2': {
- id: 'memory-2',
- name: 'Samsung PC DRAM M393A2K43BB1-CRC',
- speedMbPerS: 2400,
- sizeMb: 16000,
- energyConsumptionW: 10,
- },
- 'memory-3': {
- id: 'memory-3',
- name: 'Crucial MTA18ASF4G72PDZ-3G2E1',
- speedMbPerS: 3200,
- sizeMb: 32000,
- energyConsumptionW: 10,
- },
- 'memory-4': {
- id: 'memory-4',
- name: 'Crucial MTA9ASF2G72PZ-3G2E1',
- speedMbPerS: 3200,
- sizeMb: 16000,
- energyConsumptionW: 10,
- },
-}
-
-export const STORAGE_UNITS = {
- 'storage-1': {
- id: 'storage-1',
- name: 'Samsung EVO 2016 SATA III',
- speedMbPerS: 6000,
- sizeMb: 250000,
- energyConsumptionW: 10,
- },
- 'storage-2': {
- id: 'storage-2',
- name: 'Western Digital MTA9ASF2G72PZ-3G2E1',
- speedMbPerS: 6000,
- sizeMb: 4000000,
- energyConsumptionW: 10,
- },
-}
diff --git a/resources/experiments/config.json b/resources/experiments/config.json
index 4dbf1e91..9527923d 100644
--- a/resources/experiments/config.json
+++ b/resources/experiments/config.json
@@ -6,5 +6,7 @@
"postgresql" : "5432",
"username" : "matt",
"password" : "admin",
- "database" : "opendc"
+ "database" : "opendc",
+ "topic" : "postgres-topic",
+ "kafka" : "9092"
}
diff --git a/resources/experiments/schema.proto b/resources/experiments/schema.proto
new file mode 100644
index 00000000..2a308edd
--- /dev/null
+++ b/resources/experiments/schema.proto
@@ -0,0 +1,11 @@
+syntax = "proto2";
+
+package proto;
+
+option java_package = "org.opendc.common";
+option java_outer_classname = "ProtobufMetrics";
+
+message ProtoExport {
+ required int32 id = 1;
+ required int32 tasksactive = 2;
+} \ No newline at end of file
diff --git a/resources/experiments/sink-jdbc.properties b/resources/experiments/sink-jdbc.properties
new file mode 100644
index 00000000..4a78b2ed
--- /dev/null
+++ b/resources/experiments/sink-jdbc.properties
@@ -0,0 +1,46 @@
+#
+# Copyright 2018 Confluent Inc.
+#
+# Licensed under the Confluent Community License (the "License"); you may not use
+# this file except in compliance with the License. You may obtain a copy of the
+# License at
+#
+# http://www.confluent.io/confluent-community-license
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OF ANY KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations under the License.
+#
+
+# A simple example that copies from a topic to a Postgres database.
+# The first few settings are required for all connectors:
+# a name, the connector class to run, and the maximum number of tasks to create:
+name=postgresql-sink
+connector.class=io.confluent.connect.jdbc.JdbcSinkConnector
+tasks.max=1
+
+key.converter=org.apache.kafka.connect.storage.StringConverter
+value.converter=io.confluent.connect.protobuf.ProtobufConverter
+value.converter.schema.registry.url=http://localhost:8081
+
+# The topics to consume from - required for sink connectors like this one
+topics=postgres-topic
+
+# Configuration specific to the JDBC sink connector.
+# We want to connect to a Postgres database stored in the file test.db and auto-create tables.
+connection.url=jdbc:postgresql://127.0.0.1:5432/opendc
+
+connection.user=matt
+connection.password=admin
+auto.create=true
+
+# Define when identifiers should be quoted in DDL and DML statements.
+# The default is 'always' to maintain backward compatibility with prior versions.
+# Set this to 'never' to avoid quoting fully-qualified or simple table and column names.
+#quote.sql.identifiers=always
+
+# Here are some values that enable JSON formatted files to be ingested by Postgresql
+
+insert.mode=insert
+