Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/server-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ jobs:
run: python3 -m pytest -c pytest.toml
- name: Run tests
run: |
npm run start &
npx ts-node src/index.ts & # no nodemon: tests write files to the watched directory
sleep 5 # wait for server to start
npm run test:ci
33 changes: 2 additions & 31 deletions client/src/components/modal/DownloadModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useState, ChangeEvent } from "react";
import itl from "../../translations";
import { useStores } from "../../data";
import { ConfigInterface } from "../../data/config";
import { ProjectDetailInterface } from "../../data/project";
import { buildSequencePayload } from "../../utils/sequence-payload";

import Spinner from '../Spinner';

Expand Down Expand Up @@ -47,35 +47,6 @@ function DownloadModal({ isOpen, close }: ModalInterface) {
setChecked([]);
}

function getSequenceData() {
const seqData: {[key: string]: any} = {};

projectConfigs.forEach((config) => {
const configData = {
...config.evaluatedValues,
...config.selections,
[config.systemPath]: config.templatePath,
};
const configKeys = Object.keys(configData);

configKeys.forEach((key) => {
if (seqData[key] !== undefined) {
const initalValue = seqData[key];
if (seqData[key].indexOf(configData[key]) === -1) {
seqData[key].push(configData[key]);
}
} else {
const [modelicaPath, instancePath] = key.split("-");
if (modelicaPath !== configData[key]) {
seqData[key] = [configData[key]];
}
}
});
});

return seqData;
}

async function downloadFiles() {
setLoading(true);
// if (checked.includes(CONTROL_SEQUENCE)) {
Expand All @@ -97,7 +68,7 @@ function DownloadModal({ isOpen, close }: ModalInterface) {
const response = await fetch(`${import.meta.env.VITE_API}/sequence`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({...getSequenceData(), DEL_INFO_BOX: [false]}),
body: JSON.stringify(buildSequencePayload(projectConfigs, false)),
});

// TODO: Handle error responses which do not contain an actual file
Expand Down
17 changes: 7 additions & 10 deletions client/src/components/steps/Configs/SlideOut.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import Modal from "../../modal/Modal";
import OptionSelect from "./OptionSelect";
import { mapToDisplayOptions as mapConfigContextToDisplayOptions } from "../../../interpreter/display-option";
import { ConfigContext } from "../../../interpreter/interpreter";
import { getConfigValuesToSave } from "../../../interpreter/config-values";
import { ConfigValues } from "../../../utils/modifier-helpers";
import { removeEmpty } from "../../../utils/utils";

import "../../../styles/components/config-slide-out.scss";

Expand Down Expand Up @@ -107,15 +107,12 @@ const SlideOut = ({
event.preventDefault();
event.stopPropagation();

const validSelections: ConfigValues = {};
Object.entries(selectedValues).map(([key, value]) => {
if (context.isValidSelection(key)) {
validSelections[key] = value;
}
});
const evaluatedValues = context.getEvaluatedValues();
configStore.setSelections(config.id, validSelections);
configStore.setEvaluatedValues(config.id, removeEmpty(evaluatedValues));
const { selections, evaluatedValues } = getConfigValuesToSave(
context,
selectedValues,
);
configStore.setSelections(config.id, selections);
configStore.setEvaluatedValues(config.id, evaluatedValues);

close();
}
Expand Down
27 changes: 27 additions & 0 deletions client/src/interpreter/config-values.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { ConfigContext } from "./interpreter";
import { ConfigValues } from "../utils/modifier-helpers";
import { removeEmpty } from "../utils/utils";

/**
* Computes the values stored in a configuration when it is saved:
* the selections of displayed options, and the values evaluated by the context.
*
* Values are lazily evaluated: the context must have been mapped to display
* options (mapToDisplayOptions) beforehand, as done when the configuration
* panel is rendered.
*/
export function getConfigValuesToSave(
context: ConfigContext,
selectedValues: ConfigValues,
): { selections: ConfigValues; evaluatedValues: ConfigValues } {
const selections: ConfigValues = {};
Object.entries(selectedValues).map(([key, value]) => {
if (context.isValidSelection(key)) {
selections[key] = value;
}
});
const evaluatedValues = removeEmpty(
context.getEvaluatedValues(),
) as ConfigValues;
return { selections, evaluatedValues };
}
43 changes: 43 additions & 0 deletions client/src/utils/sequence-payload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ConfigInterface } from "../data/config";

/**
* Merges the values of all configurations into a single object mapping
* each selection path to the array of distinct values it takes
*/
export function getSequenceData(projectConfigs: ConfigInterface[]) {
const seqData: { [key: string]: any } = {};

projectConfigs.forEach((config) => {
const configData = {
...config.evaluatedValues,
...config.selections,
[config.systemPath]: config.templatePath,
};
const configKeys = Object.keys(configData);

configKeys.forEach((key) => {
if (seqData[key] !== undefined) {
if (seqData[key].indexOf(configData[key]) === -1) {
seqData[key].push(configData[key]);
}
} else {
const [modelicaPath] = key.split("-");
if (modelicaPath !== configData[key]) {
seqData[key] = [configData[key]];
}
}
});
});

return seqData;
}

/**
* Builds the payload sent to the sequence document endpoint
*/
export function buildSequencePayload(
projectConfigs: ConfigInterface[],
deleteInfoBox: boolean,
) {
return { ...getSequenceData(projectConfigs), DEL_INFO_BOX: [deleteInfoBox] };
}
Loading