diff options
author | Phil Hughes <me@iamphill.com> | 2019-01-11 13:14:51 +0300 |
---|---|---|
committer | Phil Hughes <me@iamphill.com> | 2019-01-11 13:14:51 +0300 |
commit | 8d1683f7b0173040b660a9b61e9a2d5389e1344a (patch) | |
tree | 281448892732f68a115f025c04078b7f82d6001e /app/assets/javascripts/notebook | |
parent | b682a6f8981d303e7ee7ecc4273768ee6ed66864 (diff) |
Support multiple outputs in Jupyter notebooks
Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/31910, https://gitlab.com/gitlab-org/gitlab-ce/issues/32588
Diffstat (limited to 'app/assets/javascripts/notebook')
-rw-r--r-- | app/assets/javascripts/notebook/cells/code.vue | 15 | ||||
-rw-r--r-- | app/assets/javascripts/notebook/cells/code/index.vue | 3 | ||||
-rw-r--r-- | app/assets/javascripts/notebook/cells/output/html.vue | 15 | ||||
-rw-r--r-- | app/assets/javascripts/notebook/cells/output/image.vue | 20 | ||||
-rw-r--r-- | app/assets/javascripts/notebook/cells/output/index.vue | 104 | ||||
-rw-r--r-- | app/assets/javascripts/notebook/cells/prompt.vue | 10 | ||||
-rw-r--r-- | app/assets/javascripts/notebook/index.vue | 4 |
7 files changed, 103 insertions, 68 deletions
diff --git a/app/assets/javascripts/notebook/cells/code.vue b/app/assets/javascripts/notebook/cells/code.vue index bd6736152f5..eefc801ed7a 100644 --- a/app/assets/javascripts/notebook/cells/code.vue +++ b/app/assets/javascripts/notebook/cells/code.vue @@ -1,11 +1,12 @@ <script> -import CodeCell from './code/index.vue'; +import CodeOutput from './code/index.vue'; import OutputCell from './output/index.vue'; export default { + name: 'CodeCell', components: { - 'code-cell': CodeCell, - 'output-cell': OutputCell, + CodeOutput, + OutputCell, }, props: { cell: { @@ -29,8 +30,8 @@ export default { hasOutput() { return this.cell.outputs.length; }, - output() { - return this.cell.outputs[0]; + outputs() { + return this.cell.outputs; }, }, }; @@ -38,7 +39,7 @@ export default { <template> <div class="cell"> - <code-cell + <code-output :raw-code="rawInputCode" :count="cell.execution_count" :code-css-class="codeCssClass" @@ -47,7 +48,7 @@ export default { <output-cell v-if="hasOutput" :count="cell.execution_count" - :output="output" + :outputs="outputs" :code-css-class="codeCssClass" /> </div> diff --git a/app/assets/javascripts/notebook/cells/code/index.vue b/app/assets/javascripts/notebook/cells/code/index.vue index 8bf2431c4c6..98b6cdd0944 100644 --- a/app/assets/javascripts/notebook/cells/code/index.vue +++ b/app/assets/javascripts/notebook/cells/code/index.vue @@ -3,8 +3,9 @@ import Prism from '../../lib/highlight'; import Prompt from '../prompt.vue'; export default { + name: 'CodeOutput', components: { - prompt: Prompt, + Prompt, }, props: { count: { diff --git a/app/assets/javascripts/notebook/cells/output/html.vue b/app/assets/javascripts/notebook/cells/output/html.vue index c6fc786fa76..8dc2d73af9b 100644 --- a/app/assets/javascripts/notebook/cells/output/html.vue +++ b/app/assets/javascripts/notebook/cells/output/html.vue @@ -4,13 +4,21 @@ import Prompt from '../prompt.vue'; export default { components: { - prompt: Prompt, + Prompt, }, props: { + count: { + type: Number, + required: true, + }, rawCode: { type: String, required: true, }, + index: { + type: Number, + required: true, + }, }, computed: { sanitizedOutput() { @@ -21,13 +29,16 @@ export default { }, }); }, + showOutput() { + return this.index === 0; + }, }, }; </script> <template> <div class="output"> - <prompt /> + <prompt type="Out" :count="count" :show-output="showOutput" /> <div v-html="sanitizedOutput"></div> </div> </template> diff --git a/app/assets/javascripts/notebook/cells/output/image.vue b/app/assets/javascripts/notebook/cells/output/image.vue index fe8c81398fb..f1130275525 100644 --- a/app/assets/javascripts/notebook/cells/output/image.vue +++ b/app/assets/javascripts/notebook/cells/output/image.vue @@ -6,6 +6,10 @@ export default { prompt: Prompt, }, props: { + count: { + type: Number, + required: true, + }, outputType: { type: String, required: true, @@ -14,10 +18,24 @@ export default { type: String, required: true, }, + index: { + type: Number, + required: true, + }, + }, + computed: { + imgSrc() { + return `data:${this.outputType};base64,${this.rawCode}`; + }, + showOutput() { + return this.index === 0; + }, }, }; </script> <template> - <div class="output"><prompt /> <img :src="'data:' + outputType + ';base64,' + rawCode" /></div> + <div class="output"> + <prompt type="out" :count="count" :show-output="showOutput" /> <img :src="imgSrc" /> + </div> </template> diff --git a/app/assets/javascripts/notebook/cells/output/index.vue b/app/assets/javascripts/notebook/cells/output/index.vue index bd0bcc0d819..c5ae7e7ee10 100644 --- a/app/assets/javascripts/notebook/cells/output/index.vue +++ b/app/assets/javascripts/notebook/cells/output/index.vue @@ -1,14 +1,9 @@ <script> -import CodeCell from '../code/index.vue'; -import Html from './html.vue'; -import Image from './image.vue'; +import CodeOutput from '../code/index.vue'; +import HtmlOutput from './html.vue'; +import ImageOutput from './image.vue'; export default { - components: { - 'code-cell': CodeCell, - 'html-output': Html, - 'image-output': Image, - }, props: { codeCssClass: { type: String, @@ -20,68 +15,69 @@ export default { required: false, default: 0, }, - output: { - type: Object, + outputs: { + type: Array, required: true, - default: () => ({}), }, }, - computed: { - componentName() { - if (this.output.text) { - return 'code-cell'; - } else if (this.output.data['image/png']) { - return 'image-output'; - } else if (this.output.data['text/html']) { - return 'html-output'; - } else if (this.output.data['image/svg+xml']) { - return 'html-output'; - } + data() { + return { + outputType: '', + }; + }, + methods: { + dataForType(output, type) { + let data = output.data[type]; - return 'code-cell'; - }, - rawCode() { - if (this.output.text) { - return this.output.text.join(''); + if (typeof data === 'object') { + data = data.join(''); } - return this.dataForType(this.outputType); + return data; }, - outputType() { - if (this.output.text) { - return ''; - } else if (this.output.data['image/png']) { - return 'image/png'; - } else if (this.output.data['text/html']) { - return 'text/html'; - } else if (this.output.data['image/svg+xml']) { - return 'image/svg+xml'; + getComponent(output) { + if (output.text) { + return CodeOutput; + } else if (output.data['image/png']) { + this.outputType = 'image/png'; + + return ImageOutput; + } else if (output.data['text/html']) { + this.outputType = 'text/html'; + + return HtmlOutput; + } else if (output.data['image/svg+xml']) { + this.outputType = 'image/svg+xml'; + + return HtmlOutput; } - return 'text/plain'; + this.outputType = 'text/plain'; + return CodeOutput; }, - }, - methods: { - dataForType(type) { - let data = this.output.data[type]; - - if (typeof data === 'object') { - data = data.join(''); + rawCode(output) { + if (output.text) { + return output.text.join(''); } - return data; + return this.dataForType(output, this.outputType); }, }, }; </script> <template> - <component - :is="componentName" - :output-type="outputType" - :count="count" - :raw-code="rawCode" - :code-css-class="codeCssClass" - type="output" - /> + <div> + <component + :is="getComponent(output)" + v-for="(output, index) in outputs" + :key="index" + type="output" + :output-type="outputType" + :count="count" + :index="index" + :raw-code="rawCode(output)" + :code-css-class="codeCssClass" + /> + </div> </template> diff --git a/app/assets/javascripts/notebook/cells/prompt.vue b/app/assets/javascripts/notebook/cells/prompt.vue index 3f1f239a806..1eeb61844a4 100644 --- a/app/assets/javascripts/notebook/cells/prompt.vue +++ b/app/assets/javascripts/notebook/cells/prompt.vue @@ -11,18 +11,26 @@ export default { required: false, default: 0, }, + showOutput: { + type: Boolean, + required: false, + default: true, + }, }, computed: { hasKeys() { return this.type !== '' && this.count; }, + showTypeText() { + return this.type && this.count && this.showOutput; + }, }, }; </script> <template> <div class="prompt"> - <span v-if="hasKeys"> {{ type }} [{{ count }}]: </span> + <span v-if="showTypeText"> {{ type }} [{{ count }}]: </span> </div> </template> diff --git a/app/assets/javascripts/notebook/index.vue b/app/assets/javascripts/notebook/index.vue index 6a54d0b3823..e7056c03e4a 100644 --- a/app/assets/javascripts/notebook/index.vue +++ b/app/assets/javascripts/notebook/index.vue @@ -3,8 +3,8 @@ import { MarkdownCell, CodeCell } from './cells'; export default { components: { - 'code-cell': CodeCell, - 'markdown-cell': MarkdownCell, + CodeCell, + MarkdownCell, }, props: { notebook: { |