From cafaddc388c649d3efa54335b4cea5eb6212626e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Janis=20Daniel=20Da=CC=88hne?=
 <janis.daehne2@student.uni-halle.de>
Date: Thu, 14 Nov 2019 23:06:49 +0100
Subject: [PATCH] - fixed issue where in the tutor view the save button was not
 properly disabled when there was no assessment to update   - this is possible
 with the new hasAssessment property of assessmentFullBase - we now also
 disable all assessment related inputs when there is no assessment

---
 i18n/en.ts                                    |  5 +++--
 i18n/i18nRoot.ts                              |  5 +++--
 .../feedbackPanel/feedbackEditorView.tsx      |  6 ++---
 .../feedbackPanel/feedbackPanelHeaderBar.tsx  |  2 +-
 .../sites/tutorViewSite/headerBarContent.tsx  | 22 ++++++++++++++-----
 .../manualAssessmentPanelView.tsx             | 14 ++++++------
 src/constants.ts                              |  2 +-
 src/helpers/convertersAndTransformers.ts      |  2 +-
 .../subSets/setAssessmentReducer.ts           |  1 +
 .../tutorViewSite/tutorViewSiteReducer.ts     |  5 +++--
 src/types/submissions.ts                      | 11 +++++++---
 11 files changed, 47 insertions(+), 28 deletions(-)

diff --git a/i18n/en.ts b/i18n/en.ts
index 4f6e9ada..71ee52ae 100644
--- a/i18n/en.ts
+++ b/i18n/en.ts
@@ -361,7 +361,7 @@ export const lang_en: LangObj = {
 
   //--- do editor site
   "Editor": "Editor",
-  "Editor is Markdown (Icon)" : "Editor is Markdown (Icon)",
+  "Editor supports Markdown (Icon)" : "Editor supports Markdown (Icon)",
   "Solution editor": "Solution editor",
   "Description editor": "Description editor",
   "Subsequent editor": "Subsequent editor",
@@ -545,7 +545,7 @@ export const lang_en: LangObj = {
   "Save manual assessment": "Save manual assessment",
   "This saves the manual assessment tab and the feedback for student tab" : "This saves the manual assessment tab and the feedback for student tab",
   "Manual assessment saved": "Manual assessment saved",
-  "There is no automatic assessment yet.": "There is no automatic assessment yet.",
+  "There is no automatic assessment.": "There is no automatic assessment.",
   "Normal test points": "Normal test points",
   "If there are no points then the automatic assessment option might be disabled (for the release) or there was an automatic assessment error.": "If there are no points then the automatic assessment option might be disabled (for the release) or there was an automatic assessment error.",
   "Submit test points": "Submit test points",
@@ -568,6 +568,7 @@ export const lang_en: LangObj = {
   "The submit tests results are only displayed after the automatic assessment has finished. Note that these submit tests are executed on the submit test server (not the normal test server), so there might be different settings e.g. timeouts": "The submit tests results are only displayed after the automatic assessment has finished. Note that these submit tests are executed on the submit test server (not the normal test server), so there might be different settings e.g. timeouts",
   "The release is still open.": "The release is still open.",
   "The release is still open or the automatic assessment has not finished yet": "The release is still open or the automatic assessment has not finished yet",
+  "There was no assessment object found thus the assessment cannot be saved (this normally happens if the release is still open or automatic assessment hasn't finished yet" : "There was no assessment object found thus the assessment cannot be saved (this normally happens if the release is still open or automatic assessment hasn't finished yet",
   "The release is still open or the automatic assessment has not finished yet. Some inputs might be disabled": "The release is still open or the automatic assessment has not finished yet. Some inputs might be disabled",
   "Tutor-Tests": "Tutor-Tests",
   "Tutor-Submit-Tests": "Tutor-Submit-Tests",
diff --git a/i18n/i18nRoot.ts b/i18n/i18nRoot.ts
index 1e23ceb0..db041c1f 100644
--- a/i18n/i18nRoot.ts
+++ b/i18n/i18nRoot.ts
@@ -366,7 +366,7 @@ export interface LangObj {
 
   //--- do exercise editor site
   "Editor": string
-  "Editor is Markdown (Icon)": string
+  "Editor supports Markdown (Icon)": string
   "Solution editor": string
   "Description editor": string
   "Subsequent editor": string
@@ -556,7 +556,7 @@ export interface LangObj {
   "Save manual assessment": string
   "This saves the manual assessment tab and the feedback for student tab": string
   "Manual assessment saved": string
-  "There is no automatic assessment yet.": string
+  "There is no automatic assessment.": string
   "Normal test points": string
   "If there are no points then the automatic assessment option might be disabled (for the release) or there was an automatic assessment error.": string
   "Submit test points": string
@@ -579,6 +579,7 @@ export interface LangObj {
   "The submit tests results are only displayed after the automatic assessment has finished. Note that these submit tests are executed on the submit test server (not the normal test server), so there might be different settings e.g. timeouts": string
   "The release is still open.": string
   "The release is still open or the automatic assessment has not finished yet": string
+  "There was no assessment object found thus the assessment cannot be saved (this normally happens if the release is still open or automatic assessment hasn't finished yet": string
   "The release is still open or the automatic assessment has not finished yet. Some inputs might be disabled": string
   "Tutor-Tests": string
   "Tutor-Submit-Tests": string
diff --git a/src/components/sites/tutorViewSite/feedbackPanel/feedbackEditorView.tsx b/src/components/sites/tutorViewSite/feedbackPanel/feedbackEditorView.tsx
index 6cd7efb5..564168e6 100644
--- a/src/components/sites/tutorViewSite/feedbackPanel/feedbackEditorView.tsx
+++ b/src/components/sites/tutorViewSite/feedbackPanel/feedbackEditorView.tsx
@@ -50,11 +50,11 @@ class FeedbackEditorView extends React.Component<Props, any> {
 
     const tempEditorTab: EditorTab = {
       id: 0, //this.props.assessment.userId
-      content: (this.props.assessment !== null && this.props.assessment.feedbackForStudent !== null)
+      content: (this.props.assessment.hasAssessment && this.props.assessment.feedbackForStudent !== null)
                ? this.props.assessment.feedbackForStudent
                : '',
       language: 'markdown',
-      isReadonly: this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false,
+      isReadonly: this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false || this.props.assessment.hasAssessment === false,
       fileNameWithExtensions: '',
       displayIndex: 1,
       isMainFile: true,
@@ -76,7 +76,7 @@ class FeedbackEditorView extends React.Component<Props, any> {
     }
 
     return (
-      <div className="fh" style={{overflow: 'hidden'}}>
+      <div className={`fh${this.props.assessment.hasAssessment ? '' : ' div-disabled'}`} style={{overflow: 'hidden'}}>
 
         <SimpleCodeEditorWrapper
           id={tutorViewTutorFeedbackForStudentEditor}
diff --git a/src/components/sites/tutorViewSite/feedbackPanel/feedbackPanelHeaderBar.tsx b/src/components/sites/tutorViewSite/feedbackPanel/feedbackPanelHeaderBar.tsx
index b4e926ce..4e8b2204 100644
--- a/src/components/sites/tutorViewSite/feedbackPanel/feedbackPanelHeaderBar.tsx
+++ b/src/components/sites/tutorViewSite/feedbackPanel/feedbackPanelHeaderBar.tsx
@@ -81,7 +81,7 @@ class feedbackPanelHeaderBar extends React.Component<Props, any> {
             {
               //TODO when semantic ui react has font awesome >= 5.7.x use markdown icon...
             }
-            <HelpPopup className="mar-left-half" defaultText={getI18n(this.props.langId, "Editor is Markdown (Icon)")}/>
+            <HelpPopup className="mar-left-half" defaultText={getI18n(this.props.langId, "Editor supports Markdown (Icon)")}/>
           </div>
         }
 
diff --git a/src/components/sites/tutorViewSite/headerBarContent.tsx b/src/components/sites/tutorViewSite/headerBarContent.tsx
index f25d4501..e7819a6b 100644
--- a/src/components/sites/tutorViewSite/headerBarContent.tsx
+++ b/src/components/sites/tutorViewSite/headerBarContent.tsx
@@ -156,7 +156,7 @@ class HeaderBar extends React.Component<Props, any> {
             this.props.exercise.isPermanentlyLocked === false &&
             <div className="inline-flex">
 
-              <div className={this.props.releaseFinishedAndAutomaticAssessmentHasFinished && this.props.assessment
+              <div className={this.props.releaseFinishedAndAutomaticAssessmentHasFinished && this.props.assessment.hasAssessment
                               ? 'clickable'
                               : 'div-disabled'}
                    onClick={() => {
@@ -172,21 +172,31 @@ class HeaderBar extends React.Component<Props, any> {
                 </span>
               </div>
 
-              <HelpPopup className="mar-left-half" defaultText={getI18n(this.props.langId,
-                                                                        "This saves the manual assessment tab and the feedback for student tab"
-              )}/>
+              {
+                (this.props.releaseFinishedAndAutomaticAssessmentHasFinished && this.props.assessment.hasAssessment) &&
+                <HelpPopup className="mar-left-half" defaultText={getI18n(this.props.langId,
+                                                                          "This saves the manual assessment tab and the feedback for student tab"
+                )}/>
+              }
             </div>
           }
 
           {
-            (!this.props.releaseFinishedAndAutomaticAssessmentHasFinished || !this.props.assessment) &&
+            !this.props.releaseFinishedAndAutomaticAssessmentHasFinished &&
             <HelpPopup className="mar-left-half" defaultText={getI18n(this.props.langId,
                                                                       'The release is still open or the automatic assessment has not finished yet'
             )}/>
           }
 
           {
-            this.props.exercise.isPermanentlyLocked === false || (!this.props.releaseFinishedAndAutomaticAssessmentHasFinished || !this.props.assessment) &&
+            !this.props.assessment.hasAssessment &&
+            <HelpPopup className="mar-left-half" defaultText={getI18n(this.props.langId,
+                                                                      "There was no assessment object found thus the assessment cannot be saved (this normally happens if the release is still open or automatic assessment hasn't finished yet"
+            )}/>
+          }
+
+          {
+            (this.props.exercise.isPermanentlyLocked === false || !this.props.releaseFinishedAndAutomaticAssessmentHasFinished || !this.props.assessment.hasAssessment) &&
             <SimpleVDivider/>
           }
 
diff --git a/src/components/sites/tutorViewSite/manualAssessmentPanel/manualAssessmentPanelView.tsx b/src/components/sites/tutorViewSite/manualAssessmentPanel/manualAssessmentPanelView.tsx
index 3c9d0aba..a4565119 100644
--- a/src/components/sites/tutorViewSite/manualAssessmentPanel/manualAssessmentPanelView.tsx
+++ b/src/components/sites/tutorViewSite/manualAssessmentPanel/manualAssessmentPanelView.tsx
@@ -67,13 +67,13 @@ class manualAssessmentPanelView extends React.Component<Props, any> {
 
     const submitTestPointsString = assessmentPointsToString(this.props.langId,
                                                             this.props.release.hasAutomaticAssessmentFinished,
-                                                            this.props.assessment === null,
+                                                            this.props.assessment.hasAssessment === false,
                                                             this.props.assessment.submitTestPoints,
                                                             this.props.assessment.maxSubmitTestPoints)
 
     const normalTestPointsString = assessmentPointsToString(this.props.langId,
                                                             this.props.release.hasAutomaticAssessmentFinished,
-                                                            this.props.assessment === null,
+                                                            this.props.assessment.hasAssessment === false,
                                                             this.props.assessment.normalTestPoints,
                                                             this.props.assessment.maxNormalTestPoints)
 
@@ -82,13 +82,13 @@ class manualAssessmentPanelView extends React.Component<Props, any> {
         <div className="ui form">
 
           {
-            !this.props.assessment &&
+            !this.props.assessment.hasAssessment &&
             <div style={{
               marginBottom: '1em',
               fontWeight: 'bold'
             }}>
               {
-                getI18n(this.props.langId, 'There is no automatic assessment yet.')
+                getI18n(this.props.langId, 'There is no automatic assessment.')
               }
             </div>
           }
@@ -200,7 +200,7 @@ class manualAssessmentPanelView extends React.Component<Props, any> {
                 value={this.props.assessment.manualPoints === null
                        ? ''
                        : this.props.assessment.manualPoints}
-                disabled={this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false || this.props.assessment === null}
+                disabled={this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false || this.props.assessment.hasAssessment === false}
                 type="number"
                 onFocus={selectAllTextEventHandler}
                 onChange={(e) => {
@@ -244,14 +244,14 @@ class manualAssessmentPanelView extends React.Component<Props, any> {
 
             <MaterialTextArea rows={6} resizeVertical={true}
                               enableTabInput={true}
-                              disabled={this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false || this.props.assessment === null}
+                              disabled={this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false || this.props.assessment.hasAssessment === false}
                               placeholder={`${getI18n(this.props.langId, 'Note for other tutors')}...`}
                               value={this.props.assessment.noteForOtherTutors
                                      ? this.props.assessment.noteForOtherTutors
                                      : null}
                               onChange={(event: ChangeEvent<HTMLTextAreaElement>, value: string) => {
 
-                                if (this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false || this.props.assessment === null) return
+                                if (this.props.releaseFinishedAndAutomaticAssessmentHasFinished === false || this.props.assessment.hasAssessment === false) return
 
                                 this.props.setManualAssessmentNote(value)
                               }}
diff --git a/src/constants.ts b/src/constants.ts
index 673e724f..d12b4604 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -13,7 +13,7 @@ import Logger from './helpers/logger'
  * y - breaking changes / new features
  * z - fixes, small changes
  */
-export const versionString = '2.5.11'
+export const versionString = '2.5.12'
 
 
 export const supportMail = 'yapex@informatik.uni-halle.de'
diff --git a/src/helpers/convertersAndTransformers.ts b/src/helpers/convertersAndTransformers.ts
index 986d3534..7bac4f51 100644
--- a/src/helpers/convertersAndTransformers.ts
+++ b/src/helpers/convertersAndTransformers.ts
@@ -1070,7 +1070,7 @@ function trimStart(text: string): string {
  * converts the assessment result to a string
  * @param langId
  * @param hasAutomaticAssessmentFinished
- * @param assessmentIsEmpty assessment === null ?
+ * @param assessmentIsEmpty {@link AssessmentFullBase.hasAssessment} ?
  * @param testPoints
  * @param maxTestPoints
  */
diff --git a/src/state/reducers/tutorViewSite/subSets/setAssessmentReducer.ts b/src/state/reducers/tutorViewSite/subSets/setAssessmentReducer.ts
index 92bed111..91b6c547 100644
--- a/src/state/reducers/tutorViewSite/subSets/setAssessmentReducer.ts
+++ b/src/state/reducers/tutorViewSite/subSets/setAssessmentReducer.ts
@@ -10,6 +10,7 @@ export type State = AssessmentFullBase
 
 
 export const initial: State = {
+  hasAssessment: false,
   token: '',
   firstName: '',
   lastName: '',
diff --git a/src/state/reducers/tutorViewSite/tutorViewSiteReducer.ts b/src/state/reducers/tutorViewSite/tutorViewSiteReducer.ts
index 69763ffd..6850df93 100644
--- a/src/state/reducers/tutorViewSite/tutorViewSiteReducer.ts
+++ b/src/state/reducers/tutorViewSite/tutorViewSiteReducer.ts
@@ -126,9 +126,10 @@ export type State = {
    * set via CRUD
    * managed via setAssessmentReducer
    *
-   * normally this is never null because backend returns some basic data in case there is no assessment yet
+   * this is never null because backend returns some basic data in case there is no assessment yet
+   *   if the assessment in the backend was null then the property {@link AssessmentFullBase.hasAssessment} is set to false (else true)
    */
-  readonly assessment: AssessmentFullBase | null
+  readonly assessment: AssessmentFullBase
 
   /**
    * true: go back to own exercises, false: back to group exercises
diff --git a/src/types/submissions.ts b/src/types/submissions.ts
index 12653acb..2e2cc521 100644
--- a/src/types/submissions.ts
+++ b/src/types/submissions.ts
@@ -11,12 +11,17 @@ export interface AssessmentFullBase {
    */
   //readonly id: number
 
+  /**
+   * true: assessment was != null in the backend
+   * false: assessment was null e.g. because the automatic assessment hasn't finished yet
+   *   then all nullable properties here are null...
+   */
+  readonly hasAssessment: boolean
+
   /**
    * the user token
-   * not always sent, only when needed (e.g. export)
-   * but e.g. not for tutor view
    */
-  readonly token: string | null
+  readonly token: string
 
   /**
    * the first name of the connected user
-- 
GitLab