diff --git a/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx b/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx index 719687f45c14ade3a21a723e8492a1eec3200026..075851d0350c2cffd136d0f4e4d5f578e599d16c 100644 --- a/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx +++ b/src/components/sites/doExerciseSite/consolePanel/consolePanelView.tsx @@ -20,6 +20,7 @@ import {setHideErrorOutputLines, setHideExpectedOutputLines} from '../../../../s import Logger from '../../../../helpers/logger' import {RunnableCustomProjectTestFrontendExclusive} from '../../../../types/customProjects' import {RunnableExerciseTestFrontendExclusive} from '../../../../types/exerciseEditor' +import {copyToClipboard} from '../../../../helpers/clipboard'; //const css = require('./styles.styl'); @@ -84,16 +85,113 @@ class ConsolePanelView extends React.Component<Props, any> { } } - render(): JSX.Element { + copyTestResultInputToClipboard(): void { + let protocolItemsCopy = this.getProtocolItemsSortedCopy() - if (!this.props.test && !this.props.protocolItems) { - //if we clear the console view we set both to null... - //Logger.error('console panel view can only use test or protocolItems property') - return null + const inputString = protocolItemsCopy + .filter(p => p.type === TestProtocolType.isInput) + .map(p => p.content) + .join('\n') + .toString() + + copyToClipboard(inputString) + } + copyTestResultOutputToClipboard(): void { + //the current visible state is copied + //e.g. if debug output and if expected output + let outputString = "" + + //TODO compare test result handling might be incorrect... + + //we need to get the test protocol items sorted because some e.g. expected return code not guaranteed to be the first item + let protocolItemsCopy = this.getProtocolItemsSortedCopy() + .filter(p => p.type === TestProtocolType.isOutput + || p.type === TestProtocolType.isError + || p.type === TestProtocolType.isExpectedOutput + || p.type === TestProtocolType.isCompareTestResultOk + || p.type === TestProtocolType.isCompareTestResultFile1NotFound + || p.type === TestProtocolType.isCompareTestResultFile2NotFound + || p.type === TestProtocolType.isCompareTestResultExpected + || p.type === TestProtocolType.isCompareTestResultActual + || p.type === TestProtocolType.isCompareTestResultFile2EOF + ) + + for (let i = 0; i < protocolItemsCopy.length; i++) { + let protocolItem = protocolItemsCopy[i] + + if (this.props.hideExpectedOutputLines && ( + protocolItem.type === TestProtocolType.isExpectedOutput + || protocolItem.type === TestProtocolType.isCompareTestResultExpected + ) + ) { + continue + } + + if (this.props.hideErrorOutputLines && ( + protocolItem.type === TestProtocolType.isError + || protocolItem.type === TestProtocolType.isCompareTestResultFile1NotFound + || protocolItem.type === TestProtocolType.isCompareTestResultFile2NotFound + || protocolItem.type === TestProtocolType.isCompareTestResultFile2EOF + ) + ) { + continue + } + + outputString += protocolItem.content + '\n' } - //don't add this in the mapStateToProps else we already concat a new instance thus the shallow compare from redux is false - //because we already create a new entry (with the same values but other identity) + copyToClipboard(outputString) + } + copyTestResultInputAndOutputToClipboard(): void { + //the current visible state is copied + //e.g. if debug output and if expected output + let outputString = "" + + //we need to get the test protocol items sorted because some e.g. expected return code not guaranteed to be the first item + let protocolItemsCopy = this.getProtocolItemsSortedCopy() + .filter(p => p.type === TestProtocolType.isInput + || p.type === TestProtocolType.isOutput + || p.type === TestProtocolType.isError + || p.type === TestProtocolType.isExpectedOutput + || p.type === TestProtocolType.isCompareTestResultOk + || p.type === TestProtocolType.isCompareTestResultFile1NotFound + || p.type === TestProtocolType.isCompareTestResultFile2NotFound + || p.type === TestProtocolType.isCompareTestResultExpected + || p.type === TestProtocolType.isCompareTestResultActual + || p.type === TestProtocolType.isCompareTestResultFile2EOF + ) + + for (let i = 0; i < protocolItemsCopy.length; i++) { + let protocolItem = protocolItemsCopy[i] + + if (this.props.hideExpectedOutputLines && ( + protocolItem.type === TestProtocolType.isExpectedOutput + || protocolItem.type === TestProtocolType.isCompareTestResultExpected + ) + ) { + continue + } + + if (this.props.hideErrorOutputLines && ( + protocolItem.type === TestProtocolType.isError + || protocolItem.type === TestProtocolType.isCompareTestResultFile1NotFound + || protocolItem.type === TestProtocolType.isCompareTestResultFile2NotFound + || protocolItem.type === TestProtocolType.isCompareTestResultFile2EOF + ) + ) { + continue + } + + outputString += protocolItem.content + '\n' + } + + copyToClipboard(outputString) + + } + + //copy to not mutate... + getProtocolItemsSortedCopy(): ReadonlyArray<TestProtocolItem> { + const allTestTypes = this.props.testTypes.concat([{ id: -1, displayName: 'Just Run Program', @@ -114,18 +212,10 @@ class ConsolePanelView extends React.Component<Props, any> { } if (!protocolItems) { - return null + return [] } - //only allow if we have expected output lines - //maybe this is too strange because you cannot toggle the item and then one might forget to uncheck it... - const canHideExpectedOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isExpectedOutput) - const canHideErrorOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isError) - - - //maybe not sort here but search for the items?? but we could have more than one... - //performance could be better - + //make a copy because we sort/mutate //make sure exit code is always 1. //expected always 2. //args 3. @@ -152,6 +242,40 @@ class ConsolePanelView extends React.Component<Props, any> { return 0 }) + return protocolItemsSorted as ReadonlyArray<TestProtocolItem> + } + + render(): JSX.Element { + + if (!this.props.test && !this.props.protocolItems) { + //if we clear the console view we set both to null... + //Logger.error('console panel view can only use test or protocolItems property') + return null + } + + //don't add this in the mapStateToProps else we already concat a new instance thus the shallow compare from redux is false + //because we already create a new entry (with the same values but other identity) + const allTestTypes = this.props.testTypes.concat([{ + id: -1, + displayName: 'Just Run Program', + internalName: KnownInternalTestTypes.justRunTest + }]) + + //only allow if we have expected output lines + //maybe this is too strange because you cannot toggle the item and then one might forget to uncheck it... + const canHideExpectedOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isExpectedOutput) + const canHideErrorOutputLines = true //protocolItems.some(p => p.type === TestProtocolType.isError) + + + //maybe not sort here but search for the items?? but we could have more than one... + //performance could be better + + //make sure exit code is always 1. + //expected always 2. + //args 3. + //because this looks better + // tslint:disable-next-line + let protocolItemsSorted = this.getProtocolItemsSortedCopy() // tslint:disable-next-line let expectedExitCode: number | null = null @@ -178,12 +302,13 @@ class ConsolePanelView extends React.Component<Props, any> { <List divided relaxed> { //only display header if we have some normal output... (or just don't display headers if all items are errors) - (protocolItems && protocolItems.some(p => p.type !== TestProtocolType.isError)) && + (protocolItemsSorted && protocolItemsSorted.some(p => p.type !== TestProtocolType.isError)) && <div className="console-input-output-line-header"> <div className="input-part"> <div className="flexed-well-spaced"> <div className="flexed"> + <Icon className="clickable" name="clipboard outline" onClick={() => this.copyTestResultInputToClipboard()} /> <div className="mar-right-half"> { getI18n(this.props.langId, 'Input') @@ -206,6 +331,9 @@ class ConsolePanelView extends React.Component<Props, any> { <div className="absolute-centered flexed"> + <div className="mar-right-half"> + <Icon className="clickable" name="clipboard outline" onClick={() => this.copyTestResultInputAndOutputToClipboard()} /> + </div> { canHideErrorOutputLines && this.props.displayFilterConsoleItemsOptions && @@ -280,6 +408,7 @@ class ConsolePanelView extends React.Component<Props, any> { <Icon className="not-important-colored" name="chevron right"/> <div className="flexed"> + <Icon className="clickable" name="clipboard outline" onClick={() => this.copyTestResultOutputToClipboard()} /> <div className="mar-right-half"> { getI18n(this.props.langId, 'Output') diff --git a/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx b/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx index 24e57f428f247f7c6e704891a4236e333faf904a..377627e4c99451f41c7d154ca8afb3b308fc0641 100644 --- a/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx +++ b/src/components/sites/exerciseEditorSite/exerciseEditorSite.tsx @@ -357,7 +357,7 @@ class exerciseEditorSite extends React.Component<Props & RouteComponentProps<Mat return { id: p.id, originalName: p.displayName, - sizeInBytes: p.content.length, + sizeInBytes: p.content?.length, mimeType: p.mimeType } })} diff --git a/src/constants.ts b/src/constants.ts index d2f1caf8ace7e8c607120c07941d849e96721168..21e188e577e4e5d303ae596e67f03569c771c51e 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.16.0' +export const versionString = '2.17.0' export const supportMail = 'yapex@informatik.uni-halle.de' diff --git a/src/types/testResults.ts b/src/types/testResults.ts index 7e40d24fbecfe03c642c5e386d2f7672027a8eca..dd11ba6de7e25780db98ceddb7f9469d13a78f92 100644 --- a/src/types/testResults.ts +++ b/src/types/testResults.ts @@ -313,6 +313,9 @@ export enum TestProtocolType { isCompareTestResultFile1NotFound, isCompareTestResultFile2NotFound, isCompareTestResultExpected, + /** + * actual file content (line) + */ isCompareTestResultActual, isCompareTestResultFile2EOF,