diff --git a/src/main/webui/Add_@types.patch b/src/main/webui/Add_@types.patch index 67d6171c..e92d0265 100644 --- a/src/main/webui/Add_@types.patch +++ b/src/main/webui/Add_@types.patch @@ -1,5 +1,5 @@ ---- proposalToolSchemas.ts.orig 2024-05-30 13:48:47 -+++ proposalToolSchemas.ts 2024-06-13 15:15:13 +--- proposalToolSchemas.ts.orig 2024-04-24 10:15:03 ++++ proposalToolSchemas.ts 2024-06-14 08:55:06 @@ -129,6 +129,7 @@ * An observation that is intended for calibration */ @@ -8,7 +8,28 @@ /** * any constraints on the observation */ -@@ -162,6 +163,7 @@ +@@ -149,19 +150,20 @@ + }; + + export type CalibrationTargetIntendedUse = +- | "AMPLITUDE" +- | "ATMOSPHERIC" +- | "BANDPASS" +- | "PHASE" +- | "POINTING" +- | "FOCUS" +- | "POLARIZATION" +- | "DELAY"; ++ | "Amplitude" ++ | "Atmospheric" ++ | "Bandpass" ++ | "Phase" ++ | "Pointing" ++ | "Focus" ++ | "Polarization" ++ | "Delay"; + + /** * Spatial domain, three-dimensional cartesian coordinate space. The particulars of the axis descriptions depend on the physical constraints of the instance. In Appendix B, we provide the description of a Standard Cartesian Coordinate Space instance which applies to many Astronomical cases, and may be referenced in serializations. */ export type CartesianCoordSpace = { @@ -64,6 +85,15 @@ }; export type FileUpload = Record; +@@ -563,7 +568,7 @@ + xmlId?: string; + }; + +-export type InstrumentKind = "CONTINUUM" | "SPECTROSCOPIC"; ++export type InstrumentKind = "continuum" | "spectroscopic"; + + /** + * an integer identifier that can be used as a key for lookup of an entity that is *outside this datamodel* @@ -684,6 +689,8 @@ export type ObsType = "TargetObservation" | "CalibrationObservation"; @@ -109,7 +139,25 @@ /** * a human readable description of the cycle */ -@@ -1121,6 +1136,7 @@ +@@ -1099,10 +1114,6 @@ + */ + submittedProposals?: SubmittedProposal[]; + /** +- * the proposals that have been reviewed in this cycle +- */ +- reviewedProposals?: ReviewedProposal[]; +- /** + * the proposals that have been successful and allocated time + */ + allocatedProposals?: AllocatedProposal[]; +@@ -1119,12 +1130,13 @@ + observationSessionEnd?: Date; + }; + +-export type ProposalKind = "STANDARD" | "TOO" | "SURVEY"; ++export type ProposalKind = "Standard" | "ToO" | "Survey"; + + /** * A review of a proposal */ export type ProposalReview = { @@ -117,7 +165,7 @@ /** * Description */ -@@ -1203,6 +1219,7 @@ +@@ -1207,6 +1219,7 @@ * A real value with a unit. */ export type RealQuantity = { @@ -125,7 +173,7 @@ /** * Must conform to definition of unit in VOUnit spec. */ -@@ -1234,6 +1251,8 @@ +@@ -1238,6 +1251,8 @@ * A resource that will be consumed by allocating an observation from a proposal */ export type Resource = { @@ -134,7 +182,7 @@ /** * The amount of the resource * -@@ -1264,6 +1283,7 @@ +@@ -1268,6 +1283,7 @@ * a type of resource */ export type ResourceType = { @@ -142,7 +190,53 @@ /** * the name of the resource type */ -@@ -1276,6 +1296,7 @@ +@@ -1277,52 +1293,10 @@ + }; + + /** +- * an instance of a proposal that is in review +- */ +-export type ReviewedProposal = { +- /** +- * the proposal can go on to allocation +- */ +- successful?: boolean; +- /** +- * the date when all the proposals are due +- * +- * @format date +- * @example "2022-03-10T00:00:00.000Z" +- */ +- reviewsCompleteDate?: Date; +- /** +- * the reviews +- */ +- reviews?: ProposalReview[]; +- /** +- * an instance of a proposal that has been submitted +- */ +- submitted?: SubmittedProposal; +-}; +- +-export type ReviewedProposalSynopsis = { +- /** +- * @format int64 +- */ +- dbId?: number; +- completedDate?: Date; +- successStatus?: boolean; +- /** +- * @format int64 +- */ +- numberOfReviewers?: number; +- /** +- * @format int64 +- */ +- reviewsCompleted?: number; +- proposalTitle?: string; +-}; +- +-/** * assigned to review the proposal */ export type Reviewer = { @@ -150,7 +244,7 @@ /** * person connected with the proposal */ -@@ -1307,6 +1328,8 @@ +@@ -1354,6 +1328,8 @@ /** * Science oriented definition of a spectral window. */ @@ -159,7 +253,7 @@ spectralWindowSetup?: SpectralWindowSetup; expectedSpectralLine?: ExpectedSpectralLine[]; }; -@@ -1351,6 +1374,7 @@ +@@ -1398,6 +1374,7 @@ * A SpaceFrame is specified by its reference frame (orientation), and a reference position (origin). Currently only standard reference frames are allowed. An equinox MUST be provided for pre-ICRS reference frames. A planetary ephemeris MAY be provided if relevant. If needed, but not provided, it is assumed to be 'DE405'. */ export type SpaceFrame = { @@ -167,7 +261,7 @@ /** * RefLocation defines the origin of the spatial coordinate space. This location is represented either by a standard reference position (for which the absolute location in phase space is known by definition), or a specified point in another Spatial frame. This object is used as the origin of the SpaceFrame here, but also to specify the Spatial Reference Position (refPosition) associated with other domain Frames. For example, in the Time domain, the Spatial Reference Position indicates that the 'time' values are the time that the 'event' occured at that location, which might be different from the detector location. */ -@@ -1373,6 +1397,7 @@ +@@ -1420,6 +1397,7 @@ * Specialized coordinate system for the Spatial domain. This object SHOULD include an appropriate SpaceFrame. In Appendix B, we define two standard spatial coordinate space instances (Spherical and Cartesian), which may be referenced in serializations. If a CoordSpace is not provided, it is assumed to be represented by a Standard Spherical Coordinate Space. */ export type SpaceSys = { @@ -175,7 +269,7 @@ xmlId?: string; /** * Abstract head of coordinate spaces related to physical properties. -@@ -1456,7 +1481,7 @@ +@@ -1503,7 +1481,7 @@ /** * person connected with the proposal */ @@ -184,7 +278,7 @@ uid?: string; inKeycloakRealm?: boolean; }; -@@ -1465,6 +1490,7 @@ +@@ -1512,6 +1490,7 @@ * an instance of a proposal that has been submitted */ export type SubmittedProposal = { @@ -192,7 +286,36 @@ /** * the date that the proposal was submitted * -@@ -1527,17 +1553,20 @@ +@@ -1519,6 +1498,21 @@ + * @example "2022-03-10T00:00:00.000Z" + */ + submissionDate?: Date; ++ /** ++ * the proposal can go on to allocation ++ */ ++ successful?: boolean; ++ /** ++ * the date when all the proposals are due ++ * ++ * @format date ++ * @example "2022-03-10T00:00:00.000Z" ++ */ ++ reviewsCompleteDate?: Date; ++ /** ++ * the reviews ++ */ ++ reviews?: ProposalReview[]; + /** + * a complete proposal + */ +@@ -1553,23 +1547,26 @@ + /** + * A role within the timeAllocation committee + */ +-export type TacRole = "TECHNICALREVIEWER" | "SCIENCEREVIEWER" | "CHAIR"; ++export type TacRole = "TechnicalReviewer" | "ScienceReviewer" | "Chair"; + + /** * A target source */ export type Target = { @@ -213,7 +336,7 @@ xmlId?: string; name?: string; }; -@@ -1546,6 +1575,7 @@ +@@ -1578,6 +1575,7 @@ * an observation of the scientific target */ export type TargetObservation = { @@ -221,7 +344,7 @@ /** * any constraints on the observation */ -@@ -1573,6 +1603,7 @@ +@@ -1605,6 +1603,7 @@ */ performance?: PerformanceParameters; spectrum?: ScienceSpectralWindow[]; @@ -229,7 +352,16 @@ xmlId?: string; }; -@@ -1676,6 +1707,10 @@ +@@ -1645,7 +1644,7 @@ + /** + * acceptable text formats for document submission + */ +-export type TextFormats = "LATEX" | "RST" | "ASCIIDOC"; ++export type TextFormats = "latex" | "rst" | "asciidoc"; + + /** + * A TimeFrame SHALL include a time scale and reference position. It MAY also include a reference direction. +@@ -1708,6 +1707,10 @@ * particular time range */ export type TimingWindow = { diff --git a/src/main/webui/src/ProposalEditorView/investigators/New.tsx b/src/main/webui/src/ProposalEditorView/investigators/New.tsx index 9f4e89f8..ce00e8e0 100644 --- a/src/main/webui/src/ProposalEditorView/investigators/New.tsx +++ b/src/main/webui/src/ProposalEditorView/investigators/New.tsx @@ -36,7 +36,7 @@ function AddInvestigatorPanel(): ReactElement { selectedInvestigator: 0}, validate: { selectedInvestigator: (value) => ( - value === 0 ? 'Please select an investigator' : null) + value === 0 || value === null ? 'Please select an investigator' : null) } }); const typeData = [{value: "COI", label: "CO-I"}, {value: "PI", label: "PI"}]; diff --git a/src/main/webui/src/ProposalEditorView/proposal/downloadProposal.tsx b/src/main/webui/src/ProposalEditorView/proposal/downloadProposal.tsx index 0a9eb24d..0de012d0 100644 --- a/src/main/webui/src/ProposalEditorView/proposal/downloadProposal.tsx +++ b/src/main/webui/src/ProposalEditorView/proposal/downloadProposal.tsx @@ -20,16 +20,14 @@ import {notifyError, notifyInfo} from "../../commonPanel/notifications.tsx"; * @return {Promise} the blob of the pdf. */ const generatePdf = async (element: HTMLInputElement): Promise => { - // convert overview to png. + // convert overview to png in a pdf. const canvas = await html2canvas(element); - const data = canvas.toDataURL('image/png'); const pdfMargin = 2; - // convert png to pdf. const pdfGenerator = new JSPDF(); // noinspection JSUnresolvedReference const imgProperties = - pdfGenerator.getImageProperties(data); + pdfGenerator.getImageProperties(canvas); // noinspection JSUnresolvedReference const pdfWidth = pdfGenerator.internal.pageSize.getWidth() - 2 * pdfMargin; @@ -38,7 +36,7 @@ const generatePdf = async (element: HTMLInputElement): Promise => { imgProperties.width - 2 * pdfMargin; // noinspection JSUnresolvedReference pdfGenerator.addImage( - data, 'PNG', + canvas, 'PNG', pdfMargin, pdfMargin, pdfWidth, pdfHeight, undefined, "SLOW"); diff --git a/src/main/webui/src/ProposalManagerView/proposalCycle/observatory.tsx b/src/main/webui/src/ProposalManagerView/proposalCycle/observatory.tsx index 8c199cc1..183846c2 100644 --- a/src/main/webui/src/ProposalManagerView/proposalCycle/observatory.tsx +++ b/src/main/webui/src/ProposalManagerView/proposalCycle/observatory.tsx @@ -1,15 +1,95 @@ -import {ReactElement} from "react"; -import {Text} from "@mantine/core"; +import {ReactElement, useEffect, useState} from "react"; +import {Select, Text} from "@mantine/core"; import {ManagerPanelHeader, PanelFrame} from "../../commonPanel/appearance.tsx"; import {useParams} from "react-router-dom"; +import { + fetchProposalCyclesResourceGetProposalCycleObservatory, + fetchProposalCyclesResourceReplaceCycleObservatory, ProposalCyclesResourceReplaceCycleObservatoryVariables, + useObservatoryResourceGetObservatories +} from "../../generated/proposalToolComponents.ts"; +import {notifyError, notifySuccess} from "../../commonPanel/notifications.tsx"; +import getErrorMessage from "../../errorHandling/getErrorMessage.tsx"; +import {useForm} from "@mantine/form"; +import {SubmitButton} from "../../commonButtons/save.tsx"; export default function CycleObservatoryPanel() : ReactElement { const {selectedCycleCode} = useParams(); + const [observatorySearchData, setSearchData] = useState([]); + const [formReady, setFormReady] = useState(false); + const form = useForm({ + initialValues: {selectedObservatory: 0}, + validate: { + selectedObservatory: (value) => ( + value === 0 || value === null ? 'Please select an observatory' : null) + } + }); + + const observatories = useObservatoryResourceGetObservatories({}); + + if(observatories.error) { + notifyError("Failed to load list of observatories", + getErrorMessage(observatories.error)); + } + + useEffect(() => { + if(observatories.status === 'success') { + setSearchData([]); + observatories.data?.map((item) => ( + // @ts-ignore + setSearchData((current) => [...current, { + value: String(item.dbid), label: item.name}]) + )); + + fetchProposalCyclesResourceGetProposalCycleObservatory( + {pathParams: {cycleCode: Number(selectedCycleCode)}}) + .then((observatory) => { + //FIXME: None of these three ways to set the default value seem to work + form.values.selectedObservatory = Number(observatory?._id); + //form.setFieldValue('selectedObservatory', Number(observatory?._id)); + //form.setInitialValues({selectedObservatory: Number(observatory?._id)}); + setFormReady(true); + }) + .catch((error) => notifyError("Failed to load proposal cycle details", + getErrorMessage(error))) + + } + }, [observatories.status, observatories.data]); + + const updateObservatory = form.onSubmit((val) => { + form.validate(); + const newObservatory: ProposalCyclesResourceReplaceCycleObservatoryVariables = + { + pathParams: {cycleCode: Number(selectedCycleCode)}, + body: Number(val.selectedObservatory), + // @ts-ignore + headers: {"Content-Type": "text/plain"} + }; + + fetchProposalCyclesResourceReplaceCycleObservatory(newObservatory) + .then(()=> + notifySuccess("Update observatory", "Changes saved") + ) + .catch((error) => { + notifyError("Error updating observatory", "Cause: "+getErrorMessage(error)) + }) + }) return ( - WIP: this is where you view/edit the observatory used for the cycle + Select the observatory used for this cycle + + {formReady && ( +
+