mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-14 15:14:56 -04:00
Add ability to use yaml-array for tags (#874)
This commit is contained in:
parent
bf42b9c460
commit
b2cf2f134e
8 changed files with 107 additions and 9 deletions
|
@ -16,6 +16,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||||
- `{%slideshare user/my-awesome-presentation %}` -> Embedding removed
|
- `{%slideshare user/my-awesome-presentation %}` -> Embedding removed
|
||||||
- `{%speakerdeck foobar %}` -> Embedding removed
|
- `{%speakerdeck foobar %}` -> Embedding removed
|
||||||
- The use of `sequence` as code block language ([Why?](https://hedgedoc.org/faq/))
|
- The use of `sequence` as code block language ([Why?](https://hedgedoc.org/faq/))
|
||||||
|
- Comma-separated definition of tags in the yaml-metadata
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
@ -33,6 +34,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||||
- Import content from a url
|
- Import content from a url
|
||||||
- F9 shortcut to sort lines
|
- F9 shortcut to sort lines
|
||||||
- Highlight.JS language support for `1c` was removed.
|
- Highlight.JS language support for `1c` was removed.
|
||||||
|
- Support for tag definitions in headings
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
@ -73,6 +75,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0
|
||||||
- The dark-mode is also applied to the read-only-view and can be toggled from there.
|
- The dark-mode is also applied to the read-only-view and can be toggled from there.
|
||||||
- Access tokens for the CLI and 3rd-party-clients can be managed in the user profile.
|
- Access tokens for the CLI and 3rd-party-clients can be managed in the user profile.
|
||||||
- Change editor font to "Fira Code"
|
- Change editor font to "Fira Code"
|
||||||
|
- Note tags can be set as yaml-array in frontmatter
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
37
cypress/integration/metadata.spec.ts
Normal file
37
cypress/integration/metadata.spec.ts
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
describe('yaml-metadata: tags', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.visit('/n/features')
|
||||||
|
cy.get('.CodeMirror textarea')
|
||||||
|
.type('{ctrl}a', { force: true })
|
||||||
|
.type('{backspace}')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('show deprecation notice on old syntax', () => {
|
||||||
|
cy.get('.CodeMirror textarea')
|
||||||
|
.type('---\ntags: a, b, c\n---')
|
||||||
|
cy.get('.splitter.right .w-100.h-100 .alert.alert-warning')
|
||||||
|
.should('be.visible')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('show no deprecation notice on yaml-array (1)', () => {
|
||||||
|
cy.get('.CodeMirror textarea')
|
||||||
|
.type('---\ntags: [\'a\', \'b\', \'c\']\n---')
|
||||||
|
cy.get('.splitter.right .w-100.h-100 .alert.alert-warning')
|
||||||
|
.should('not.exist')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('show no deprecation notice on yaml-array (2)', () => {
|
||||||
|
cy.get('.CodeMirror textarea')
|
||||||
|
.type('---\ntags:\n - a\nb\nc\n')
|
||||||
|
.type('{backspace}{backspace}{backspace}{backspace}')
|
||||||
|
.type('---')
|
||||||
|
cy.get('.splitter.right .w-100.h-100 .alert.alert-warning')
|
||||||
|
.should('not.exist')
|
||||||
|
})
|
||||||
|
})
|
|
@ -185,6 +185,7 @@
|
||||||
"untitledNote": "Untitled",
|
"untitledNote": "Untitled",
|
||||||
"placeholder": "← Start by entering a title here\n===\nVisit the features page if you don't know what to do.\nHappy hacking :)",
|
"placeholder": "← Start by entering a title here\n===\nVisit the features page if you don't know what to do.\nHappy hacking :)",
|
||||||
"invalidYaml": "The yaml-header is invalid. See <0></0> for more information.",
|
"invalidYaml": "The yaml-header is invalid. See <0></0> for more information.",
|
||||||
|
"deprecatedTags": "The comma-separated definition of tags in the yaml-metadata is deprecated. Use a yaml-array instead.",
|
||||||
"infoToc": "Structure your note with headings to see a table-of-contents here.",
|
"infoToc": "Structure your note with headings to see a table-of-contents here.",
|
||||||
"help": {
|
"help": {
|
||||||
"shortcuts": {
|
"shortcuts": {
|
||||||
|
@ -453,7 +454,8 @@
|
||||||
"why": "Why?",
|
"why": "Why?",
|
||||||
"successfullyCopied": "Copied!",
|
"successfullyCopied": "Copied!",
|
||||||
"copyError": "Error while copying!",
|
"copyError": "Error while copying!",
|
||||||
"errorOccurred": "An error occurred"
|
"errorOccurred": "An error occurred",
|
||||||
|
"readForMoreInfo": "Read here for more information"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"chooseMethod": "Choose method",
|
"chooseMethod": "Choose method",
|
||||||
|
|
|
@ -69,7 +69,7 @@ describe('yaml tests', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('tags only', () => {
|
it('tags only (old syntax)', () => {
|
||||||
testMetadata(`---
|
testMetadata(`---
|
||||||
tags: test123, abc
|
tags: test123, abc
|
||||||
___
|
___
|
||||||
|
@ -78,10 +78,41 @@ describe('yaml tests', () => {
|
||||||
tags: 'test123, abc'
|
tags: 'test123, abc'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
tags: ['test123', 'abc']
|
tags: ['test123', 'abc'],
|
||||||
|
deprecatedTagsSyntax: true
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('tags only', () => {
|
||||||
|
testMetadata(`---
|
||||||
|
tags:
|
||||||
|
- test123
|
||||||
|
- abc
|
||||||
|
___
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
tags: ['test123', 'abc']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tags: ['test123', 'abc'],
|
||||||
|
deprecatedTagsSyntax: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('tags only (alternative syntax)', () => {
|
||||||
|
testMetadata(`---
|
||||||
|
tags: ['test123', 'abc']
|
||||||
|
___
|
||||||
|
`,
|
||||||
|
{
|
||||||
|
tags: ['test123', 'abc']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tags: ['test123', 'abc'],
|
||||||
|
deprecatedTagsSyntax: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
it('breaks only', () => {
|
it('breaks only', () => {
|
||||||
testMetadata(`---
|
testMetadata(`---
|
||||||
breaks: false
|
breaks: false
|
||||||
|
|
|
@ -11,7 +11,7 @@ type iso6391 = 'aa' | 'ab' | 'af' | 'am' | 'ar' | 'ar-ae' | 'ar-bh' | 'ar-dz' |
|
||||||
export interface RawYAMLMetadata {
|
export interface RawYAMLMetadata {
|
||||||
title: string | undefined
|
title: string | undefined
|
||||||
description: string | undefined
|
description: string | undefined
|
||||||
tags: string | undefined
|
tags: string | string[] | undefined
|
||||||
robots: string | undefined
|
robots: string | undefined
|
||||||
lang: string | undefined
|
lang: string | undefined
|
||||||
dir: string | undefined
|
dir: string | undefined
|
||||||
|
@ -27,6 +27,7 @@ export class YAMLMetaData {
|
||||||
title: string
|
title: string
|
||||||
description: string
|
description: string
|
||||||
tags: string[]
|
tags: string[]
|
||||||
|
deprecatedTagsSyntax: boolean
|
||||||
robots: string
|
robots: string
|
||||||
lang: iso6391
|
lang: iso6391
|
||||||
dir: 'ltr' | 'rtl'
|
dir: 'ltr' | 'rtl'
|
||||||
|
@ -53,7 +54,16 @@ export class YAMLMetaData {
|
||||||
transition: 'none',
|
transition: 'none',
|
||||||
theme: 'white'
|
theme: 'white'
|
||||||
} */
|
} */
|
||||||
this.tags = rawData?.tags?.split(',').map(entry => entry.trim()) ?? []
|
if (typeof rawData?.tags === 'string') {
|
||||||
|
this.tags = rawData?.tags?.split(',').map(entry => entry.trim()) ?? []
|
||||||
|
this.deprecatedTagsSyntax = true
|
||||||
|
} else if (typeof rawData?.tags === 'object') {
|
||||||
|
this.tags = rawData?.tags?.filter(tag => tag !== null) ?? []
|
||||||
|
this.deprecatedTagsSyntax = false
|
||||||
|
} else {
|
||||||
|
this.tags = []
|
||||||
|
this.deprecatedTagsSyntax = false
|
||||||
|
}
|
||||||
this.opengraph = rawData?.opengraph ? new Map<string, string>(Object.entries(rawData.opengraph)) : new Map<string, string>()
|
this.opengraph = rawData?.opengraph ? new Map<string, string>(Object.entries(rawData.opengraph)) : new Map<string, string>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import React, { useCallback, useMemo, useRef, useState } from 'react'
|
import React, { useCallback, useMemo, useRef, useState } from 'react'
|
||||||
import { Alert } from 'react-bootstrap'
|
import { Alert } from 'react-bootstrap'
|
||||||
import { Trans } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { TocAst } from 'markdown-it-toc-done-right'
|
import { TocAst } from 'markdown-it-toc-done-right'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
import { ApplicationState } from '../../redux'
|
||||||
import { InternalLink } from '../common/links/internal-link'
|
import { InternalLink } from '../common/links/internal-link'
|
||||||
|
import links from '../../links.json'
|
||||||
|
import { TranslatedExternalLink } from '../common/links/translated-external-link'
|
||||||
import { ShowIf } from '../common/show-if/show-if'
|
import { ShowIf } from '../common/show-if/show-if'
|
||||||
import { RawYAMLMetadata, YAMLMetaData } from '../editor/yaml-metadata/yaml-metadata'
|
import { RawYAMLMetadata, YAMLMetaData } from '../editor/yaml-metadata/yaml-metadata'
|
||||||
import { BasicMarkdownRenderer } from './basic-markdown-renderer'
|
import { BasicMarkdownRenderer } from './basic-markdown-renderer'
|
||||||
|
@ -40,8 +44,10 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
|
||||||
wide
|
wide
|
||||||
}) => {
|
}) => {
|
||||||
const allReplacers = useReplacerInstanceListCreator(onTaskCheckedChange)
|
const allReplacers = useReplacerInstanceListCreator(onTaskCheckedChange)
|
||||||
|
useTranslation()
|
||||||
|
|
||||||
const [yamlError, setYamlError] = useState(false)
|
const [yamlError, setYamlError] = useState(false)
|
||||||
|
const yamlDeprecatedTags = useSelector((state: ApplicationState) => state.documentContent.metadata.deprecatedTagsSyntax)
|
||||||
|
|
||||||
const rawMetaRef = useRef<RawYAMLMetadata>()
|
const rawMetaRef = useRef<RawYAMLMetadata>()
|
||||||
const firstHeadingRef = useRef<string>()
|
const firstHeadingRef = useRef<string>()
|
||||||
|
@ -79,10 +85,17 @@ export const FullMarkdownRenderer: React.FC<FullMarkdownRendererProps & Addition
|
||||||
<ShowIf condition={yamlError}>
|
<ShowIf condition={yamlError}>
|
||||||
<Alert variant='warning' dir='auto'>
|
<Alert variant='warning' dir='auto'>
|
||||||
<Trans i18nKey='editor.invalidYaml'>
|
<Trans i18nKey='editor.invalidYaml'>
|
||||||
<InternalLink text='yaml-metadata' href='/n/yaml-metadata' className='text-dark'/>
|
<InternalLink text='yaml-metadata' href='/n/yaml-metadata' className='text-primary'/>
|
||||||
</Trans>
|
</Trans>
|
||||||
</Alert>
|
</Alert>
|
||||||
</ShowIf>
|
</ShowIf>
|
||||||
|
<ShowIf condition={yamlDeprecatedTags}>
|
||||||
|
<Alert variant='warning' dir='auto'>
|
||||||
|
<Trans i18nKey='editor.deprecatedTags' />
|
||||||
|
<br/>
|
||||||
|
<TranslatedExternalLink i18nKey={'common.readForMoreInfo'} href={links.faq} className={'text-primary'}/>
|
||||||
|
</Alert>
|
||||||
|
</ShowIf>
|
||||||
<BasicMarkdownRenderer className={className} wide={wide} content={content} componentReplacers={allReplacers}
|
<BasicMarkdownRenderer className={className} wide={wide} content={content} componentReplacers={allReplacers}
|
||||||
markdownIt={markdownIt} documentReference={documentElement}
|
markdownIt={markdownIt} documentReference={documentElement}
|
||||||
onBeforeRendering={clearMetadata}/>
|
onBeforeRendering={clearMetadata}/>
|
||||||
|
|
|
@ -17,7 +17,7 @@ export const DeprecationWarning: React.FC = () => {
|
||||||
<Alert className={'mt-2'} variant={'warning'}>
|
<Alert className={'mt-2'} variant={'warning'}>
|
||||||
<Trans i18nKey={'renderer.sequence.deprecationWarning'}/>
|
<Trans i18nKey={'renderer.sequence.deprecationWarning'}/>
|
||||||
|
|
||||||
<TranslatedExternalLink i18nKey={'common.why'} className={'text-primary'} href={links.faq}/>
|
<TranslatedExternalLink i18nKey={'common.readForMoreInfo'} className={'text-primary'} href={links.faq}/>
|
||||||
</Alert>
|
</Alert>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,8 @@ import {
|
||||||
DocumentContent,
|
DocumentContent,
|
||||||
DocumentContentAction,
|
DocumentContentAction,
|
||||||
DocumentContentActionType,
|
DocumentContentActionType,
|
||||||
SetDocumentContentAction, SetDocumentMetadataAction,
|
SetDocumentContentAction,
|
||||||
|
SetDocumentMetadataAction,
|
||||||
SetNoteIdAction
|
SetNoteIdAction
|
||||||
} from './types'
|
} from './types'
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ export const initialState: DocumentContent = {
|
||||||
title: '',
|
title: '',
|
||||||
description: '',
|
description: '',
|
||||||
tags: [],
|
tags: [],
|
||||||
|
deprecatedTagsSyntax: false,
|
||||||
robots: '',
|
robots: '',
|
||||||
lang: 'en',
|
lang: 'en',
|
||||||
dir: 'ltr',
|
dir: 'ltr',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue