Skip to content
Draft
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
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,17 @@
"graphql": "16.11.0",
"graphql-tag": "2.12.6",
"lodash-es": "4.17.21",
"markdown-it": "14.1.0",
"mitt": "3.0.1",
"myst-parser": "1.5.12",
"myst-theme": "0.0.0",
"myst-to-html": "1.5.12",
"nprogress": "1.0.0-1",
"preact": "10.26.5",
"rehype-stringify": "^10.0.1",
"simple-icons": "2.19.0",
"subscriptions-transport-ws": "0.11.0",
"svg-pan-zoom": "3.6.2",
"unified": "11.0.5",
"vue": "3.5.16",
"vue-i18n": "11.1.3",
"vue-router": "4.5.1",
Expand Down
11 changes: 11 additions & 0 deletions renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@
"addLabels": [
"data workflows team"
]
},
{
"groupName": "MyST packages",
"matchPackageNames": [
"myst-*",
"rehype-stringify",
"unified"
],
"schedule": [
"on the 23rd day of the month"
]
}
],
"vulnerabilityAlerts": {
Expand Down
16 changes: 12 additions & 4 deletions src/components/Markdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,17 @@
</template>

<script>
import MarkdownIt from 'markdown-it'

const md = new MarkdownIt()
import { mystParser } from 'myst-parser'
import { State, transform, mystToHast, formatHtml } from 'myst-to-html'
import rehypeStringify from 'rehype-stringify'
import { unified } from 'unified'

const pipe = unified()
.use(mystParser)
.use(transform, new State())
.use(mystToHast)
.use(formatHtml)
.use(rehypeStringify)

export default {
name: 'Markdown',
Expand All @@ -40,7 +48,7 @@ export default {

computed: {
html () {
return md.render(this.markdown)
return pipe.processSync(this.markdown).value
}
}
}
Expand Down
13 changes: 7 additions & 6 deletions src/components/cylc/Info.vue
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</v-expansion-panel-title>
<v-expansion-panel-text>
<dl>
<dt>Title</dt>
<dd>{{ taskMetadata.title }}</dd>
<v-divider />
<dt>Description</dt>
<dd><span class="markup">{{ taskMetadata.description }}</span></dd>
<dt><h1 class="meta-title">{{ taskMetadata.title || '(Title)'}}</h1></dt>
<v-divider />
<dt>URL</dt>
<dd>
Expand All @@ -75,9 +71,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
</a>
</dd>
<v-divider />
<dt>Description</dt>
<dd><Markdown :markdown="taskMetadata.description || ''"/></dd>
<v-divider />
<template v-for="(value, key) in customMetadata" :key="key">
<dt>{{ key }}</dt>
<dd><span class="markup">{{ value }}</span></dd>
<dd><Markdown :markdown="value"/></dd>
<v-divider />
</template>
</dl>
Expand Down Expand Up @@ -168,12 +167,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<script>
import { useJobTheme } from '@/composables/localStorage'
import GraphNode from '@/components/cylc/GraphNode.vue'
import Markdown from '@/components/Markdown.vue'
import { formatCompletion } from '@/utils/outputs'

export default {
name: 'InfoComponent',

components: {
Markdown,
GraphNode,
},

Expand Down
11 changes: 9 additions & 2 deletions src/services/mock/json/infoView.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@
"meanElapsedTime": "10",
"meta": {
"title": "Failed Task",
"description": "A task that always fails!",
"description": "# A task that always fails!\n\n - Bullet point\n - Bullet 🐜\n",
"URL": "https://cylc.org",
"userDefined": {
"my custom field": "My custom value!"
"my custom field": "My custom value!",
"Links and images": "[Great Auk - link example](https://en.wikipedia.org/wiki/Great_Auk)\n\n![Great Auk](https://upload.wikimedia.org/wikipedia/commons/4/4e/Great_Auk_%28Pinguinis_impennis%29_specimen%2C_Kelvingrove%2C_Glasgow_-_geograph.org.uk_-_1108249.jpg)",
"Admonitions": ":::{note}\nB-flat\n:::\n\n:::{tip}\nMy Shed\n:::\n\n:::{warning}\nLive without...\n:::\n\n:::{danger}\nMouse\n:::\n\n:::{caution}\nHorses\n:::",
"Titles": "## Level 2\n### Level 3\n#### Level 4\n##### Level 5\n###### Level 6",
"Tables": "| Header 1 | Header 2 |\n| -------- | -------- |\n| Row 1 | Row 2 |\n| Row 3 | Row 4 |\n",
"List Table": ":::{list-table}\n:header-rows: 1\n\n* - Header 1\n - Header 2\n* - Row 1\n - Row 2\n* - Row 3\n - Row 4\n:::\n",
"Code blocks": "```python\n# Python\nprint('Hello, world!')\n```\n\n```bash\n# bash\nls -l\n```\n",
"Maths": "Inline math: $E=mc^2$ and block math:\n\n$$\n\\int_0^1 x^2 \\, dx = \\frac{1}{3}\n$$\n"
}
}
},
Expand Down
198 changes: 181 additions & 17 deletions src/styles/cylc/_markdown.scss
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like the myst-theme package provides CSS: https://github.com/jupyter-book/myst-theme/tree/main/styles

Can we just import this from there? We can always apply additional modifications if needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that will work - a quick look at that library suggests that it doesn't really contain things like .admonition which are required.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yet they seem to have good support for admonitions on their website?

https://jupyter-book.github.io/myst-theme/?path=/docs/components-admonitions--docs

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jupyter-book is using myst-to-react, which looks like it's different output to myst-to-html. I can see if I can do that, but it sounds a bit wierd.

Copy link
Member Author

@wxtim wxtim May 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spent quite a while trying to address this as well as trying to get the maths parsing working - these threads seemed to hint at solutions, but I was unable to- get them working:

There was a suggestion that css could be included like this:

  .use(rehypeDocument, {
    css: ['myst.css', 'https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css'],
    js: ["https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.js", "https://cdn.jsdelivr.net/npm/[email protected]/dist/contrib/auto-render.min.js"],
    script: `document.addEventListener("DOMContentLoaded", (event) => {
        renderMathInElement(document.body, {
            delimiters: [{
                    left: "$$",
                    right: "$$",
                    display: true
                },
                {
                    left: "$",
                    right: "$",
                    display: false
                }
            ]
        });
    });`
  })

But I haven't been able to make that work either.

Original file line number Diff line number Diff line change
@@ -1,19 +1,183 @@
/**
* Copyright (C) NIWA & British Crown (Met Office) & Contributors.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// This is code taken from jupyter-book/mystmd project
// https://github.com/jupyter-book/mystmd/blob/01efd316754aee61f0e95fb5b1c5c9b35a23c5b9/packages/myst-parser/myst.css
// and modified to fit the needs of the Cylc project.
// The original license is as follows:

// The MIT License (MIT)

// Copyright (c) 2024 Project Jupyter

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

aside.admonition {
width: 95%;
margin: 1.5625em auto;
padding: 0 0.6rem 0.8rem !important;
overflow: hidden;
page-break-inside: avoid;
border-left: 0.2rem solid #007bff;
border-radius: 0.1rem;
box-shadow: 0 0.2rem 0.5rem rgba(0, 0, 0, 0.05), 0 0 0.05rem rgba(0, 0, 0, 0.1);
}

aside.admonition > p.admonition-title {
position: relative;
margin: 0 -0.6rem !important;
/* Changed the final from 2rem, without icon */
padding: 0.4rem 0.6rem 0.4rem 1rem;
font-weight: 700;
background-color: #e7f2fa;
}

aside.admonition.attention {
border-left-color: #fd7e14;
}
aside.admonition.attention > header {
background-color: #ffedcc;
}
aside.admonition.caution {
border-left-color: #fd7e14;
}
aside.admonition.caution > header {
background-color: #ffedcc;
}
aside.admonition.warning {
border-left-color: #dc3545;
}
aside.admonition.warning > header {
background-color: #fdf3f2;
}
aside.admonition.danger {
border-left-color: #dc3545;
}
aside.admonition.danger > header {
background-color: #fdf3f2;
}
aside.admonition.error {
border-left-color: #dc3545;
}
aside.admonition.error > header {
background-color: #fdf3f2;
}
aside.admonition.hint {
border-left-color: #ffc107;
}
aside.admonition.hint > header {
background-color: #fff6dd;
}
aside.admonition.important {
border-left-color: #007bff;
}
aside.admonition.important > header {
background-color: #e7f2fa;
}
aside.admonition.note {
border-left-color: #007bff;
}
aside.admonition.note > header {
background-color: #e7f2fa;
}
aside.admonition.tip {
border-left-color: #ffc107;
}
aside.admonition.tip > header {
background-color: #fff6dd;
}

aside.admonition > p {
padding: 0 1.4rem;
}

abbr {
text-decoration: none;
border-bottom: 1px solid #ddd;
cursor: help;
}

a {
color: #0071bc;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

code {
font-size: 95%;
font-family: monospace;
color: #e83e8c;
word-wrap: break-word;
}

pre {
width: calc(100% - 20px - 3em);
padding: 10px;
background-color: #fafafa;
color: #222;
line-height: 1.2em;
border: 1px solid #c9c9c9;
margin: 1.5em 0;
box-shadow: 1px 1px 1px #d8d8d8;
}
pre > code {
font-size: 87.5%;
font-family: monospace;
color: #222;
}

hr {
width: 80%;
margin: 20px auto;
}

blockquote {
color: rgb(90, 90, 90);
padding: 0.1rem 1rem;
border-left: 0.2rem solid #aaa;
}

figure {
text-align: center;
}

figure > figcaption {
color: rgb(90, 90, 90);
font-size: 90%;
}

figure > figcaption .caption-number {
font-weight: 700;
padding-right: 5px;
}

.math .MathJax {
outline: none;
}
div.math.numbered {
width: calc(100% - 50px);
margin: 0 auto;
}
div.math.numbered:before {
content: '(' attr(number) ')';
float: right;
}

.markdown {
p, ul, ol {
Expand All @@ -30,4 +194,4 @@
.v-theme--dark & code {
background-color: rgba(255, 255, 255, 0.1);
}
}
}
39 changes: 39 additions & 0 deletions tests/component/specs/info.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ import { Tokens } from '@/utils/uid'
const DESCRIPTION = `Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi.

# New Section

H{sub}\`2\`O, and 5{sup}\`th\` of November.

\`\`\`{list-table} A Liszt Table
:header-rows: 1

* - Piece
- Year
* - Hungarian Rhapsody No. 2
- 1847
* - La Campanella
- 1851
* - Liebestraum No. 3
- 1850
`
const TOKENS = new Tokens('~user/workflow//1234/foo')
const TASK = {
Expand Down Expand Up @@ -155,6 +171,21 @@ describe('Info component', () => {
.get('.metadata-panel a:first') // the URL should be an anchor
.should('have.attr', 'href', 'https://cylc.org')
.contains(/^https:\/\/cylc.org$/)
// Markdonw allows the adding of additional titles:
.get('h1').eq(1)
.contains('New Section')
// Markdown subscripts and superscripts should be rendered:
.get('sub')
.contains('2')
.get('sup')
.contains('th')
// Markdown tables should be rendered:
.get('table')
.should('be.visible')
.get('table tr')
.contains('Hungarian Rhapsody No. 2')
.get('table th')
.contains('Piece')

// the prerequisites panel
cy.get('.prerequisites-panel.v-expansion-panel--active').should('be.visible')
Expand Down Expand Up @@ -278,5 +309,13 @@ describe('Info component', () => {
panelExpansion: [0, 1, 2],
}
})

// the metadata panel contains default values where there is no data:
cy.get('.metadata-panel.v-expansion-panel--active').should('be.visible')
.contains('(Title)')
.get('.metadata-panel')
.contains('Description')
.get('.metadata-panel')
.contains('URL')
})
})
Loading