mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2026-06-23 04:10:17 +00:00
fix(frontend): accessibility issues and other linting problems
Signed-off-by: Erik Michelson <github@erik.michelson.eu>
This commit is contained in:
committed by
Philip Molares
parent
50d0585ccb
commit
8988e3868f
@@ -20,7 +20,8 @@
|
||||
"jest/valid-expect": "error",
|
||||
"jest/expect-expect": ["error", {
|
||||
"assertFunctionNames": ["expect*", "screen.*", "test*"]
|
||||
}]
|
||||
}],
|
||||
"nextjs/no-img-element": "off"
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
|
||||
@@ -76,3 +76,9 @@
|
||||
.overflow-y-hidden {
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
.unstyled-button {
|
||||
appearance: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@ const mockedCommonAppState = {
|
||||
canEdit: false
|
||||
}
|
||||
] as NoteGroupPermissionEntryInterface[],
|
||||
sharedToUsers: [] as NoteUserPermissionEntryInterface[]
|
||||
sharedToUsers: [] as NoteUserPermissionEntryInterface[],
|
||||
publiclyVisible: false
|
||||
}
|
||||
},
|
||||
user: {
|
||||
|
||||
+6
-6
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Copy to clipboard button show an error text if clipboard api isn't available 1`] = `
|
||||
exports[`Copy to clipboard button show an error text if clipboard api isn't available: renders copy button 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="copy-button btn btn-dark btn-sm"
|
||||
@@ -12,7 +12,7 @@ exports[`Copy to clipboard button show an error text if clipboard api isn't avai
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Copy to clipboard button show an error text if clipboard api isn't available 2`] = `
|
||||
exports[`Copy to clipboard button show an error text if clipboard api isn't available: renders copy button with tooltip 1`] = `
|
||||
<div>
|
||||
<button
|
||||
aria-describedby="copied_35a35a31-c259-48c4-b75a-8da99859dcdb"
|
||||
@@ -25,7 +25,7 @@ exports[`Copy to clipboard button show an error text if clipboard api isn't avai
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Copy to clipboard button shows an error text if writing failed 1`] = `
|
||||
exports[`Copy to clipboard button shows an error text if writing failed: renders copy button 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="copy-button btn btn-dark btn-sm"
|
||||
@@ -37,7 +37,7 @@ exports[`Copy to clipboard button shows an error text if writing failed 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Copy to clipboard button shows an error text if writing failed 2`] = `
|
||||
exports[`Copy to clipboard button shows an error text if writing failed: renders copy button with tooltip 1`] = `
|
||||
<div>
|
||||
<button
|
||||
aria-describedby="copied_35a35a31-c259-48c4-b75a-8da99859dcdb"
|
||||
@@ -50,7 +50,7 @@ exports[`Copy to clipboard button shows an error text if writing failed 2`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Copy to clipboard button shows an success text if writing succeeded 1`] = `
|
||||
exports[`Copy to clipboard button shows an success text if writing succeeded: renders copy button 1`] = `
|
||||
<div>
|
||||
<button
|
||||
class="copy-button btn btn-dark btn-sm"
|
||||
@@ -62,7 +62,7 @@ exports[`Copy to clipboard button shows an success text if writing succeeded 1`]
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Copy to clipboard button shows an success text if writing succeeded 2`] = `
|
||||
exports[`Copy to clipboard button shows an success text if writing succeeded: renders copy button with tooltip 1`] = `
|
||||
<div>
|
||||
<button
|
||||
aria-describedby="copied_35a35a31-c259-48c4-b75a-8da99859dcdb"
|
||||
|
||||
+6
-6
@@ -31,9 +31,9 @@ describe('Copy to clipboard button', () => {
|
||||
jest.resetModules()
|
||||
})
|
||||
|
||||
const testButton = async (expectSuccess: boolean) => {
|
||||
const expectButtonSnapshot = async (expectSuccess: boolean) => {
|
||||
const view = render(<CopyToClipboardButton content={copyContent} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('renders copy button')
|
||||
const button = await screen.findByTitle('renderer.highlightCode.copyCode')
|
||||
act(() => {
|
||||
button.click()
|
||||
@@ -41,7 +41,7 @@ describe('Copy to clipboard button', () => {
|
||||
const tooltip = await screen.findByRole('tooltip')
|
||||
expect(tooltip).toHaveTextContent(expectSuccess ? 'copyOverlay.success' : 'copyOverlay.error')
|
||||
expect(tooltip).toHaveAttribute('id', overlayId)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('renders copy button with tooltip')
|
||||
}
|
||||
|
||||
const mockClipboard = (copyIsSuccessful: boolean): jest.Mock => {
|
||||
@@ -58,13 +58,13 @@ describe('Copy to clipboard button', () => {
|
||||
|
||||
it('shows an success text if writing succeeded', async () => {
|
||||
const writeTextToClipboardSpy = mockClipboard(true)
|
||||
await testButton(true)
|
||||
await expectButtonSnapshot(true)
|
||||
expect(writeTextToClipboardSpy).toHaveBeenCalledWith(copyContent)
|
||||
})
|
||||
|
||||
it('shows an error text if writing failed', async () => {
|
||||
const writeTextToClipboardSpy = mockClipboard(false)
|
||||
await testButton(false)
|
||||
await expectButtonSnapshot(false)
|
||||
expect(writeTextToClipboardSpy).toHaveBeenCalledWith(copyContent)
|
||||
})
|
||||
|
||||
@@ -73,6 +73,6 @@ describe('Copy to clipboard button', () => {
|
||||
clipboard: undefined
|
||||
})
|
||||
|
||||
await testButton(false)
|
||||
await expectButtonSnapshot(false)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -72,7 +72,7 @@ export const ProfilePictureSelectField: React.FC<ProfilePictureSelectFieldProps>
|
||||
onChange={onSetProviderPicture}
|
||||
/>
|
||||
<Form.Check.Label>
|
||||
{/* oxlint-disable-next-line @next/next/no-img-element */}
|
||||
{/* oxlint-disable-next-line jsx_a11y/img-redundant-alt */}
|
||||
<img src={photoUrl} alt={'Profile picture provided by the identity provider'} height={48} width={48} />
|
||||
</Form.Check.Label>
|
||||
</Form.Check>
|
||||
@@ -84,7 +84,7 @@ export const ProfilePictureSelectField: React.FC<ProfilePictureSelectFieldProps>
|
||||
onChange={onSetFallbackPicture}
|
||||
/>
|
||||
<Form.Check.Label>
|
||||
{/* oxlint-disable-next-line @next/next/no-img-element */}
|
||||
{/* oxlint-disable-next-line jsx_a11y/img-redundant-alt */}
|
||||
<img alt={'Fallback profile picture'} src={fallbackUrl} height={48} width={48} />
|
||||
</Form.Check.Label>
|
||||
</Form.Check>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
import { createNumberRangeArray } from './number-range'
|
||||
|
||||
describe('number range', () => {
|
||||
describe('createNumberRangeArray', () => {
|
||||
it('creates an empty number range', () => {
|
||||
expect(createNumberRangeArray(0)).toEqual([])
|
||||
})
|
||||
@@ -15,6 +15,6 @@ describe('number range', () => {
|
||||
})
|
||||
|
||||
it('fails with a negative range', () => {
|
||||
expect(() => createNumberRangeArray(-1)).toThrow()
|
||||
expect(() => createNumberRangeArray(-1)).toThrow('Invalid array length')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import React from 'react'
|
||||
|
||||
export interface PageItemProps {
|
||||
onClick: (index: number) => void
|
||||
index: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a number and adds an onClick handler to it.
|
||||
*
|
||||
* @param index The number to render
|
||||
* @param onClick The onClick Handler
|
||||
*/
|
||||
export const PagerItem: React.FC<PageItemProps> = ({ index, onClick }) => {
|
||||
return (
|
||||
<li className='page-item'>
|
||||
<span className='page-link' role='button' onClick={() => onClick(index)}>
|
||||
{index + 1}
|
||||
</span>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import { PagerItem } from './pager-item'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import { Pagination } from 'react-bootstrap'
|
||||
|
||||
export interface PaginationProps {
|
||||
numberOfPageButtonsToShowAfterAndBeforeCurrent: number
|
||||
onPageChange: (pageIndex: number) => void
|
||||
lastPageIndex: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a pagination menu to move back and forth between pages.
|
||||
*
|
||||
* @param numberOfPageButtonsToShowAfterAndBeforeCurrent The number of buttons that should be shown before and after the current button.
|
||||
* @param onPageChange The callback when one of the buttons is clicked
|
||||
* @param lastPageIndex The index of the last page
|
||||
*/
|
||||
export const PagerPagination: React.FC<PaginationProps> = ({
|
||||
numberOfPageButtonsToShowAfterAndBeforeCurrent,
|
||||
onPageChange,
|
||||
lastPageIndex
|
||||
}) => {
|
||||
if (numberOfPageButtonsToShowAfterAndBeforeCurrent % 2 !== 0) {
|
||||
throw new Error('number of pages to show must be even!')
|
||||
}
|
||||
|
||||
const [pageIndex, setPageIndex] = useState(0)
|
||||
const correctedPageIndex = Math.min(pageIndex, lastPageIndex)
|
||||
const wantedUpperPageIndex = correctedPageIndex + numberOfPageButtonsToShowAfterAndBeforeCurrent
|
||||
const wantedLowerPageIndex = correctedPageIndex - numberOfPageButtonsToShowAfterAndBeforeCurrent
|
||||
|
||||
useEffect(() => {
|
||||
onPageChange(pageIndex)
|
||||
}, [onPageChange, pageIndex])
|
||||
|
||||
const correctedLowerPageIndex = useMemo(
|
||||
() =>
|
||||
Math.min(
|
||||
Math.max(Math.min(wantedLowerPageIndex, wantedLowerPageIndex + lastPageIndex - wantedUpperPageIndex), 0),
|
||||
lastPageIndex
|
||||
),
|
||||
[wantedLowerPageIndex, lastPageIndex, wantedUpperPageIndex]
|
||||
)
|
||||
|
||||
const correctedUpperPageIndex = useMemo(
|
||||
() =>
|
||||
Math.max(Math.min(Math.max(wantedUpperPageIndex, wantedUpperPageIndex - wantedLowerPageIndex), lastPageIndex), 0),
|
||||
[wantedUpperPageIndex, lastPageIndex, wantedLowerPageIndex]
|
||||
)
|
||||
|
||||
const paginationItemsBefore = useMemo(() => {
|
||||
return new Array(correctedPageIndex - correctedLowerPageIndex).map((k, index) => {
|
||||
const itemIndex = correctedLowerPageIndex + index
|
||||
return <PagerItem key={itemIndex} index={itemIndex} onClick={setPageIndex} />
|
||||
})
|
||||
}, [correctedPageIndex, correctedLowerPageIndex, setPageIndex])
|
||||
|
||||
const paginationItemsAfter = useMemo(() => {
|
||||
return new Array(correctedUpperPageIndex - correctedPageIndex).map((k, index) => {
|
||||
const itemIndex = correctedPageIndex + index + 1
|
||||
return <PagerItem key={itemIndex} index={itemIndex} onClick={setPageIndex} />
|
||||
})
|
||||
}, [correctedUpperPageIndex, correctedPageIndex, setPageIndex])
|
||||
|
||||
return (
|
||||
<Pagination dir='ltr'>
|
||||
{correctedLowerPageIndex > 0 && (
|
||||
<>
|
||||
<PagerItem key={0} index={0} onClick={setPageIndex} />
|
||||
<Pagination.Ellipsis disabled />
|
||||
</>
|
||||
)}
|
||||
{paginationItemsBefore}
|
||||
<Pagination.Item active>{correctedPageIndex + 1}</Pagination.Item>
|
||||
{paginationItemsAfter}
|
||||
{correctedUpperPageIndex < lastPageIndex && (
|
||||
<>
|
||||
<Pagination.Ellipsis disabled />
|
||||
<PagerItem key={lastPageIndex} index={lastPageIndex} onClick={setPageIndex} />
|
||||
</>
|
||||
)}
|
||||
</Pagination>
|
||||
)
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import React, { Fragment, useEffect, useMemo } from 'react'
|
||||
|
||||
export interface PagerPageProps {
|
||||
pageIndex: number
|
||||
numberOfElementsPerPage: number
|
||||
onLastPageIndexChange: (lastPageIndex: number) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a limited number of the given children.
|
||||
*
|
||||
* @param children The children to render
|
||||
* @param numberOfElementsPerPage The number of elements per page
|
||||
* @param pageIndex Which page of the children to render
|
||||
* @param onLastPageIndexChange A callback to notify about changes to the maximal page number
|
||||
*/
|
||||
export const Pager: React.FC<PropsWithChildren<PagerPageProps>> = ({
|
||||
children,
|
||||
numberOfElementsPerPage,
|
||||
pageIndex,
|
||||
onLastPageIndexChange
|
||||
}) => {
|
||||
const maxPageIndex = Math.ceil(React.Children.count(children) / numberOfElementsPerPage) - 1
|
||||
const correctedPageIndex = Math.min(maxPageIndex, Math.max(0, pageIndex))
|
||||
|
||||
useEffect(() => {
|
||||
onLastPageIndexChange(maxPageIndex)
|
||||
}, [children, maxPageIndex, numberOfElementsPerPage, onLastPageIndexChange])
|
||||
|
||||
const filteredChildren = useMemo(() => {
|
||||
return React.Children.toArray(children).filter((value, index) => {
|
||||
const pageOfElement = Math.floor(index / numberOfElementsPerPage)
|
||||
return pageOfElement === correctedPageIndex
|
||||
})
|
||||
}, [children, numberOfElementsPerPage, correctedPageIndex])
|
||||
|
||||
return <Fragment>{filteredChildren}</Fragment>
|
||||
}
|
||||
@@ -165,7 +165,11 @@ export const EditorPane: React.FC<EditorPaneProps> = ({ scrollState, onScroll, o
|
||||
}, [dispatchUiNotification, userMayEdit])
|
||||
|
||||
return (
|
||||
// The pane has event handlers for tracking the active scroll source. It is not directly interactive.
|
||||
// oxlint-disable-next-line jsx_a11y/no-static-element-interactions
|
||||
<div
|
||||
role={'region'}
|
||||
aria-label={'Editor pane'}
|
||||
className={`d-flex flex-column h-100 position-relative`}
|
||||
onTouchStart={onMakeScrollSource}
|
||||
onMouseEnter={onMakeScrollSource}
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
*/
|
||||
import { mockI18n } from '../../../../test-utils/mock-i18n'
|
||||
import { FrontmatterLinter } from './frontmatter-linter'
|
||||
import { mockEditorView } from './single-line-regex-linter.spec'
|
||||
import type { Diagnostic } from '@codemirror/lint'
|
||||
import { t } from 'i18next'
|
||||
import { mockEditorView } from './mock-editor-view'
|
||||
|
||||
const testFrontmatterLinter = (
|
||||
editorContent: string,
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 The HedgeDoc developers (see AUTHORS file)
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
import type { EditorState, Text } from '@codemirror/state'
|
||||
import type { EditorView } from '@codemirror/view'
|
||||
import { Mock } from 'ts-mockery'
|
||||
|
||||
/**
|
||||
* Mocks a CodeMirror editor view instance.
|
||||
* @param content The mocked content of the editor view
|
||||
* @returns A mocked editor view instance
|
||||
*/
|
||||
export const mockEditorView = (content: string): EditorView => {
|
||||
const docMock = Mock.of<Text>()
|
||||
docMock.toString = () => content
|
||||
return Mock.of<EditorView>({
|
||||
state: Mock.of<EditorState>({
|
||||
doc: docMock
|
||||
}),
|
||||
dispatch: jest.fn()
|
||||
})
|
||||
}
|
||||
+12
-18
@@ -6,22 +6,16 @@
|
||||
import { mockI18n } from '../../../../test-utils/mock-i18n'
|
||||
import { SingleLineRegexLinter } from './single-line-regex-linter'
|
||||
import type { Diagnostic } from '@codemirror/lint'
|
||||
import type { EditorState, Text } from '@codemirror/state'
|
||||
import type { EditorView } from '@codemirror/view'
|
||||
import { Mock } from 'ts-mockery'
|
||||
import { mockEditorView } from './mock-editor-view'
|
||||
|
||||
export const mockEditorView = (content: string): EditorView => {
|
||||
const docMock = Mock.of<Text>()
|
||||
docMock.toString = () => content
|
||||
return Mock.of<EditorView>({
|
||||
state: Mock.of<EditorState>({
|
||||
doc: docMock
|
||||
}),
|
||||
dispatch: jest.fn()
|
||||
})
|
||||
}
|
||||
|
||||
const testSingleLineRegexLinter = (
|
||||
/**
|
||||
* Expects that the linter returns the expected diagnostics for the given regex and content.
|
||||
* @param regex The regex that should be used to find the expected diagnostics
|
||||
* @param replace The function that should be used to replace the matched text
|
||||
* @param content The content that should be used to find the expected diagnostics
|
||||
* @param expectedDiagnostics Array of expected diagnostics that should be returned by the linter
|
||||
*/
|
||||
const expectSingleLineRegexLinterResult = (
|
||||
regex: RegExp,
|
||||
replace: (match: string) => string,
|
||||
content: string,
|
||||
@@ -48,7 +42,7 @@ describe('SingleLineRegexLinter', () => {
|
||||
await mockI18n()
|
||||
})
|
||||
it('works for a simple regex', () => {
|
||||
testSingleLineRegexLinter(/^foo$/, () => 'bar', 'This\nis\na\ntest\nfoo\nbar\n123', [
|
||||
expectSingleLineRegexLinterResult(/^foo$/, () => 'bar', 'This\nis\na\ntest\nfoo\nbar\n123', [
|
||||
{
|
||||
from: 15,
|
||||
to: 18
|
||||
@@ -56,7 +50,7 @@ describe('SingleLineRegexLinter', () => {
|
||||
])
|
||||
})
|
||||
it('works for a multiple hits', () => {
|
||||
testSingleLineRegexLinter(/^foo$/, () => 'bar', 'This\nfoo\na\ntest\nfoo\nbar\n123', [
|
||||
expectSingleLineRegexLinterResult(/^foo$/, () => 'bar', 'This\nfoo\na\ntest\nfoo\nbar\n123', [
|
||||
{
|
||||
from: 5,
|
||||
to: 8
|
||||
@@ -68,6 +62,6 @@ describe('SingleLineRegexLinter', () => {
|
||||
])
|
||||
})
|
||||
it('work if there are no hits', () => {
|
||||
testSingleLineRegexLinter(/^nothing$/, () => 'bar', 'This\nfoo\na\ntest\nfoo\nbar\n123', [])
|
||||
expectSingleLineRegexLinterResult(/^nothing$/, () => 'bar', 'This\nfoo\na\ntest\nfoo\nbar\n123', [])
|
||||
})
|
||||
})
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ export const TableSizePickerPopover = React.forwardRef<HTMLDivElement, TableSize
|
||||
createNumberRangeArray(10).map((col: number) => {
|
||||
const selected = tableSize && row < tableSize.rows && col < tableSize.columns
|
||||
return (
|
||||
<div
|
||||
<button
|
||||
key={`${row}_${col}`}
|
||||
className={concatCssClasses(styles.cell, { [styles.selected]: selected })}
|
||||
{...cypressAttribute('selected', selected ? 'true' : 'false')}
|
||||
|
||||
+2
-7
@@ -17,15 +17,12 @@ jest.mock('../../../../../../redux/note-details/methods')
|
||||
jest.mock('../../../../../notifications/ui-notification-boundary')
|
||||
jest.mock('../../../../../../hooks/common/use-application-state')
|
||||
|
||||
const deletePromise = Promise.resolve()
|
||||
const markAsPrimaryPromise = Promise.resolve({ name: 'mock-alias', isPrimaryAlias: true })
|
||||
|
||||
describe('AliasesListEntry', () => {
|
||||
beforeEach(async () => {
|
||||
await mockI18n()
|
||||
mockUiNotifications()
|
||||
jest.spyOn(AliasModule, 'deleteAlias').mockImplementation(() => deletePromise)
|
||||
jest.spyOn(AliasModule, 'markAliasAsPrimary').mockImplementation(() => markAsPrimaryPromise)
|
||||
jest.spyOn(AliasModule, 'deleteAlias').mockImplementation(() => Promise.resolve())
|
||||
jest.spyOn(AliasModule, 'markAliasAsPrimary').mockImplementation(() => Promise.resolve())
|
||||
jest.spyOn(NoteDetailsReduxModule, 'updateMetadata').mockImplementation(() => Promise.resolve())
|
||||
})
|
||||
|
||||
@@ -67,7 +64,6 @@ describe('AliasesListEntry', () => {
|
||||
buttonRemove.click()
|
||||
})
|
||||
expect(AliasModule.deleteAlias).toBeCalledWith('mock-alias-other')
|
||||
await deletePromise
|
||||
expect(NoteDetailsReduxModule.updateMetadata).toBeCalled()
|
||||
})
|
||||
|
||||
@@ -82,7 +78,6 @@ describe('AliasesListEntry', () => {
|
||||
buttonMakePrimary.click()
|
||||
})
|
||||
expect(AliasModule.markAliasAsPrimary).toBeCalledWith('mock-alias-other')
|
||||
await markAsPrimaryPromise
|
||||
expect(NoteDetailsReduxModule.updateMetadata).toBeCalled()
|
||||
})
|
||||
|
||||
|
||||
-1
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
import { useApplicationState } from '../../../../../hooks/common/use-application-state'
|
||||
import { useIsNotePinned } from '../../../../../hooks/common/use-is-note-pinned'
|
||||
import { concatCssClasses } from '../../../../../utils/concat-css-classes'
|
||||
import { SidebarButton } from '../../sidebar-button/sidebar-button'
|
||||
import type { SpecificSidebarEntryProps } from '../../types'
|
||||
import React, { useCallback, useState } from 'react'
|
||||
|
||||
@@ -34,7 +34,10 @@ exports[`Splitter resize can change size with mouse 1`] = `
|
||||
BootstrapIconMock_ArrowLeft
|
||||
</button>
|
||||
<span
|
||||
aria-orientation="vertical"
|
||||
class="grabber"
|
||||
role="separator"
|
||||
tabindex="0"
|
||||
>
|
||||
BootstrapIconMock_ArrowLeftRight
|
||||
</span>
|
||||
@@ -62,7 +65,7 @@ exports[`Splitter resize can change size with mouse 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Splitter resize can change size with touch 1`] = `
|
||||
exports[`Splitter resize can change size with touch: touch initial 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="flex-fill flex-row d-flex "
|
||||
@@ -96,7 +99,10 @@ exports[`Splitter resize can change size with touch 1`] = `
|
||||
BootstrapIconMock_ArrowLeft
|
||||
</button>
|
||||
<span
|
||||
aria-orientation="vertical"
|
||||
class="grabber"
|
||||
role="separator"
|
||||
tabindex="0"
|
||||
>
|
||||
BootstrapIconMock_ArrowLeftRight
|
||||
</span>
|
||||
@@ -124,7 +130,7 @@ exports[`Splitter resize can change size with touch 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Splitter resize can change size with touch 2`] = `
|
||||
exports[`Splitter resize can change size with touch: touch move to left 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="flex-fill flex-row d-flex "
|
||||
@@ -158,7 +164,10 @@ exports[`Splitter resize can change size with touch 2`] = `
|
||||
BootstrapIconMock_ArrowLeft
|
||||
</button>
|
||||
<span
|
||||
aria-orientation="vertical"
|
||||
class="grabber"
|
||||
role="separator"
|
||||
tabindex="0"
|
||||
>
|
||||
BootstrapIconMock_ArrowLeftRight
|
||||
</span>
|
||||
@@ -186,7 +195,7 @@ exports[`Splitter resize can change size with touch 2`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Splitter resize can change size with touch 3`] = `
|
||||
exports[`Splitter resize can change size with touch: touch move to middle 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="flex-fill flex-row d-flex "
|
||||
@@ -220,7 +229,10 @@ exports[`Splitter resize can change size with touch 3`] = `
|
||||
BootstrapIconMock_ArrowLeft
|
||||
</button>
|
||||
<span
|
||||
aria-orientation="vertical"
|
||||
class="grabber"
|
||||
role="separator"
|
||||
tabindex="0"
|
||||
>
|
||||
BootstrapIconMock_ArrowLeftRight
|
||||
</span>
|
||||
@@ -248,7 +260,7 @@ exports[`Splitter resize can change size with touch 3`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Splitter resize can change size with touch 4`] = `
|
||||
exports[`Splitter resize can change size with touch: touch move to right 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="flex-fill flex-row d-flex "
|
||||
@@ -282,7 +294,10 @@ exports[`Splitter resize can change size with touch 4`] = `
|
||||
BootstrapIconMock_ArrowLeft
|
||||
</button>
|
||||
<span
|
||||
aria-orientation="vertical"
|
||||
class="grabber"
|
||||
role="separator"
|
||||
tabindex="0"
|
||||
>
|
||||
BootstrapIconMock_ArrowLeftRight
|
||||
</span>
|
||||
|
||||
@@ -66,7 +66,14 @@ export const SplitDivider: React.FC<SplitDividerProps> = ({
|
||||
<Button variant={focusLeft ? 'secondary' : 'light'} onClick={onLeftButtonClick}>
|
||||
<UiIcon icon={IconArrowLeft} />
|
||||
</Button>
|
||||
<span onMouseDown={onGrab} onTouchStart={onGrab} className={styles['grabber']}>
|
||||
{/* oxlint-disable-next-line jsx_a11y/no-static-element-interactions */}
|
||||
<span
|
||||
role={'separator'}
|
||||
aria-orientation={'vertical'}
|
||||
tabIndex={0}
|
||||
onMouseDown={onGrab}
|
||||
onTouchStart={onGrab}
|
||||
className={styles['grabber']}>
|
||||
<UiIcon icon={IconArrowLeftRight} />
|
||||
</span>
|
||||
<Button variant={focusRight ? 'secondary' : 'light'} onClick={onRightButtonClick}>
|
||||
|
||||
@@ -59,7 +59,7 @@ describe('Splitter', () => {
|
||||
|
||||
it('can change size with touch', async () => {
|
||||
const view = render(<Splitter left={<>left</>} right={<>right</>} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('touch initial')
|
||||
const divider = await screen.findByTestId('splitter-divider')
|
||||
const target: EventTarget = Mock.of<EventTarget>()
|
||||
const defaultTouchEvent: Omit<Touch, 'clientX'> = {
|
||||
@@ -87,7 +87,7 @@ describe('Splitter', () => {
|
||||
})
|
||||
)
|
||||
fireEvent.touchEnd(window)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('touch move to left')
|
||||
|
||||
fireEvent.touchStart(divider, {})
|
||||
fireEvent.touchMove(
|
||||
@@ -100,7 +100,7 @@ describe('Splitter', () => {
|
||||
})
|
||||
)
|
||||
fireEvent.touchCancel(window)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('touch move to right')
|
||||
|
||||
fireEvent.touchMove(
|
||||
window,
|
||||
@@ -111,7 +111,7 @@ describe('Splitter', () => {
|
||||
]
|
||||
})
|
||||
)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('touch move to middle')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -142,7 +142,13 @@ export const Splitter: React.FC<SplitterProps> = ({ additionalContainerClassName
|
||||
resizingInProgress ? ' ' + styles.resizing : ''
|
||||
}`}>
|
||||
{resizingInProgress && (
|
||||
// oxlint-disable-next-line jsx_a11y/no-static-element-interactions
|
||||
<div
|
||||
role={'separator'}
|
||||
aria-orientation={'vertical'}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
aria-valuenow={adjustedRelativeSplitValue}
|
||||
className={styles['move-overlay']}
|
||||
onTouchMove={onMove}
|
||||
onMouseMove={onMove}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
} from 'react-bootstrap-icons'
|
||||
import styles from './caret.module.scss'
|
||||
import { UiIcon } from '../../common/icons/ui-icon'
|
||||
import { concatCssClasses } from '../../../utils/concat-css-classes'
|
||||
|
||||
interface CaretProps {
|
||||
left: boolean
|
||||
@@ -32,8 +33,13 @@ export const Caret: React.FC<CaretProps> = ({ active, left, onClick }) => {
|
||||
const inactiveIcon = useMemo(() => (left ? IconCaretLeftEmpty : IconCaretRightEmpty), [left])
|
||||
|
||||
return (
|
||||
<div onClick={active ? onClick : undefined} className={`${active ? styles.active : undefined}`}>
|
||||
<button
|
||||
onClick={active ? onClick : undefined}
|
||||
disabled={!active}
|
||||
className={concatCssClasses('unstyled-button', {
|
||||
[styles.active]: active
|
||||
})}>
|
||||
<UiIcon icon={active ? activeIcon : inactiveIcon} size={2} />
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export const PinnedNoteCard: React.FC<NoteExploreEntryInterface> = ({ title, las
|
||||
const lastChangedString = useMemo(() => formatChangedAt(lastChangedAt), [lastChangedAt])
|
||||
|
||||
const onClickUnpin = useCallback(
|
||||
(event: MouseEvent<HTMLDivElement>) => {
|
||||
(event: MouseEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault()
|
||||
unpinNote(primaryAlias).catch(
|
||||
showErrorNotificationBuilder('explore.pinnedNotes.unpinError', { name: primaryAlias })
|
||||
@@ -46,10 +46,10 @@ export const PinnedNoteCard: React.FC<NoteExploreEntryInterface> = ({ title, las
|
||||
<Card className={`${styles.card}`} as={Link} href={`/n/${primaryAlias}`}>
|
||||
<Card.Body className={`${styles.cardBody}`}>
|
||||
<div className={'d-flex align-items-center'}>
|
||||
<div onClick={onClickUnpin} title={labelUnpinNote}>
|
||||
<button type={'button'} onClick={onClickUnpin} title={labelUnpinNote} className={'unstyled-button'}>
|
||||
<UiIcon icon={IconPinned} size={1.5} className={`${styles.bookmark}`} />
|
||||
<div className={`${styles.star}`} />
|
||||
</div>
|
||||
</button>
|
||||
<span className={'me-2'}>
|
||||
<NoteTypeIcon noteType={type} size={3} />
|
||||
</span>
|
||||
|
||||
+10
-10
@@ -8,7 +8,16 @@ exports[`motd modal doesn't render a modal if no motd has been fetched 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`motd modal renders a modal if a motd was fetched and can dismiss it 1`] = `
|
||||
exports[`motd modal renders a modal if a motd was fetched and can dismiss it: modal is dismissed 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
This is a mock implementation of a Modal:
|
||||
Modal is invisible
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`motd modal renders a modal if a motd was fetched and can dismiss it: renders motd modal 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
This is a mock implementation of a Modal:
|
||||
@@ -38,12 +47,3 @@ exports[`motd modal renders a modal if a motd was fetched and can dismiss it 1`]
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`motd modal renders a modal if a motd was fetched and can dismiss it 2`] = `
|
||||
<div>
|
||||
<span>
|
||||
This is a mock implementation of a Modal:
|
||||
Modal is invisible
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -58,13 +58,13 @@ describe('motd modal', () => {
|
||||
</MotdProvider>
|
||||
)
|
||||
await screen.findByTestId('motd-renderer')
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('renders motd modal')
|
||||
|
||||
const button = await screen.findByTestId('motd-dismiss')
|
||||
await act<void>(() => {
|
||||
button.click()
|
||||
})
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('modal is dismissed')
|
||||
})
|
||||
|
||||
it("doesn't render a modal if no motd has been fetched", async () => {
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ exports[`Settings On-Off Button Group accepts custom labels 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Settings On-Off Button Group can switch value 1`] = `
|
||||
exports[`Settings On-Off Button Group can switch value: defaults to off 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="btn-group"
|
||||
@@ -56,7 +56,7 @@ exports[`Settings On-Off Button Group can switch value 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Settings On-Off Button Group can switch value 2`] = `
|
||||
exports[`Settings On-Off Button Group can switch value: is set to on 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="btn-group"
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ describe('Settings On-Off Button Group', () => {
|
||||
const onSelect = (newValue: boolean) => (value = newValue)
|
||||
|
||||
const view = render(<OnOffButtonGroup name={'test'} value={value} onSelect={onSelect} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('defaults to off')
|
||||
const onButton = await screen.findByTestId('onOffButtonGroupOn')
|
||||
await act<void>(() => {
|
||||
onButton.click()
|
||||
@@ -23,7 +23,7 @@ describe('Settings On-Off Button Group', () => {
|
||||
expect(value).toBeTruthy()
|
||||
|
||||
view.rerender(<OnOffButtonGroup name={'test'} value={value} onSelect={onSelect} />)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('is set to on')
|
||||
const offButton = await screen.findByTestId('onOffButtonGroupOff')
|
||||
await act<void>(() => {
|
||||
offButton.click()
|
||||
|
||||
@@ -34,7 +34,7 @@ export const JumpAnchor: React.FC<JumpAnchorProps> = ({ jumpTargetId, children,
|
||||
)
|
||||
|
||||
return (
|
||||
<a {...props} onClick={jumpToTargetId}>
|
||||
<a {...props} onClick={jumpToTargetId} href={`#${jumpTargetId}`}>
|
||||
{children}
|
||||
</a>
|
||||
)
|
||||
|
||||
+3
-2
@@ -37,6 +37,7 @@ export interface ClickShieldProps extends PropsWithChildren<PropsWithDataCypress
|
||||
* @param targetDescription The name of the target service
|
||||
* @param hoverIcon The name of an icon that should be shown in the preview
|
||||
* @param fallbackBackgroundColor A color that should be used if no background image was provided or could be loaded.
|
||||
* @param fallbackLink The link that should be shown in the print preview.
|
||||
* @param children The children element that should be shielded.
|
||||
*/
|
||||
export const ClickShield: React.FC<ClickShieldProps> = ({
|
||||
@@ -130,7 +131,7 @@ export const ClickShield: React.FC<ClickShieldProps> = ({
|
||||
return (
|
||||
<Fragment>
|
||||
<span className={containerClassName} {...cypressId(props['data-cypress-id'])}>
|
||||
<span className={`d-inline-block ratio ratio-16x9 ${styles['click-shield']}`} onClick={doShowChildren}>
|
||||
<button className={`d-inline-block ratio ratio-16x9 ${styles['click-shield']}`} onClick={doShowChildren}>
|
||||
{previewBackground}
|
||||
<span className={`${styles['preview-hover']}`}>
|
||||
<span>
|
||||
@@ -138,7 +139,7 @@ export const ClickShield: React.FC<ClickShieldProps> = ({
|
||||
</span>
|
||||
{icon}
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
<PrintLink link={fallbackLink} />
|
||||
</Fragment>
|
||||
|
||||
@@ -87,7 +87,7 @@ export const UiNotificationBoundary: React.FC<PropsWithChildren> = ({ children }
|
||||
(messageI18nKey: string, messageI18nOptions: Record<string, unknown> = {}, showErrorMessage = false) =>
|
||||
(error: Error): void => {
|
||||
log.error(t(messageI18nKey, messageI18nOptions), error)
|
||||
dispatchUiNotification('common.errorOccurred', messageI18nKey, {
|
||||
dispatchUiNotification('common.errorOccurred', messageI18nKey, {
|
||||
contentI18nOptions: showErrorMessage
|
||||
? { ...messageI18nOptions, errorMessage: error.message }
|
||||
: messageI18nOptions,
|
||||
|
||||
+7
-7
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`AbcFrame renders a music sheet 1`] = `
|
||||
exports[`AbcFrame renders a music sheet: before rendering abcjs 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="m-3 d-flex align-items-center justify-content-center"
|
||||
@@ -10,7 +10,7 @@ exports[`AbcFrame renders a music sheet 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AbcFrame renders a music sheet 2`] = `
|
||||
exports[`AbcFrame renders a music sheet: with rendered abcjs 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="abcjs-score bg-white text-black svg-container"
|
||||
@@ -2444,7 +2444,7 @@ exports[`AbcFrame renders a music sheet 2`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AbcFrame renders an error if abcjs file can't be loaded 1`] = `
|
||||
exports[`AbcFrame renders an error if abcjs file can't be loaded: before rendering abcjs 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="m-3 d-flex align-items-center justify-content-center"
|
||||
@@ -2454,7 +2454,7 @@ exports[`AbcFrame renders an error if abcjs file can't be loaded 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AbcFrame renders an error if abcjs file can't be loaded 2`] = `
|
||||
exports[`AbcFrame renders an error if abcjs file can't be loaded: with loading error message shown 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="fade alert alert-danger show"
|
||||
@@ -2465,7 +2465,7 @@ exports[`AbcFrame renders an error if abcjs file can't be loaded 2`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AbcFrame renders an error if abcjs render function crashes 1`] = `
|
||||
exports[`AbcFrame renders an error if abcjs render function crashes: before rendering abcjs 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="m-3 d-flex align-items-center justify-content-center"
|
||||
@@ -2475,13 +2475,13 @@ exports[`AbcFrame renders an error if abcjs render function crashes 1`] = `
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`AbcFrame renders an error if abcjs render function crashes 2`] = `
|
||||
exports[`AbcFrame renders an error if abcjs render function crashes: with rendering error message shown 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
<h3>
|
||||
This is a mock for ApplicationErrorAlert.
|
||||
</h3>
|
||||
Props:
|
||||
Props:
|
||||
<code>
|
||||
{}
|
||||
</code>
|
||||
|
||||
@@ -36,9 +36,9 @@ describe('AbcFrame', () => {
|
||||
/>
|
||||
)
|
||||
const view = render(element)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('before rendering abcjs')
|
||||
expect(await screen.findByText('Sheet Music for "Speed the Plough"')).toBeInTheDocument()
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('with rendered abcjs')
|
||||
})
|
||||
|
||||
it("renders an error if abcjs file can't be loaded", async () => {
|
||||
@@ -53,9 +53,9 @@ describe('AbcFrame', () => {
|
||||
/>
|
||||
)
|
||||
const view = render(element)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('before rendering abcjs')
|
||||
expect(await screen.findByText('common.errorWhileLoading')).toBeInTheDocument()
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('with loading error message shown')
|
||||
})
|
||||
|
||||
it('renders an error if abcjs render function crashes', async () => {
|
||||
@@ -72,8 +72,8 @@ describe('AbcFrame', () => {
|
||||
/>
|
||||
)
|
||||
const view = render(element)
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('before rendering abcjs')
|
||||
expect(await screen.findByText('editor.embeddings.abcJs.errorWhileRendering')).toBeInTheDocument()
|
||||
expect(view.container).toMatchSnapshot()
|
||||
expect(view.container).toMatchSnapshot('with rendering error message shown')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -44,7 +44,14 @@ export const GistFrame: React.FC<IdProps> = ({ id }) => {
|
||||
src={`https://gist.github.com/${id}.pibb`}
|
||||
/>
|
||||
<span className={`${styles['gist-resizer-row']} d-print-none`}>
|
||||
<span className={styles['gist-resizer']} onMouseDown={onStart} onTouchStart={onStart} />
|
||||
{/* oxlint-disable-next-line jsx_a11y/no-static-element-interactions */}
|
||||
<span
|
||||
role={'separator'}
|
||||
aria-orientation={'horizontal'}
|
||||
className={styles['gist-resizer']}
|
||||
onMouseDown={onStart}
|
||||
onTouchStart={onStart}
|
||||
/>
|
||||
</span>
|
||||
</ClickShield>
|
||||
)
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@
|
||||
import { replaceVimeoLinkMarkdownItPlugin } from './replace-vimeo-link'
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
describe('Replace youtube link', () => {
|
||||
describe('Replace vimeo link', () => {
|
||||
let markdownIt: MarkdownIt
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -22,7 +22,7 @@ describe('Replace youtube link', () => {
|
||||
;['player.', ''].forEach((subdomain) => {
|
||||
;['vimeo.com'].forEach((domain) => {
|
||||
const origin = `${protocol}${subdomain}${domain}/`
|
||||
describe(origin, () => {
|
||||
describe(`Replacer for ${origin}`, () => {
|
||||
const validUrl = `${origin}23237102`
|
||||
it(`can detect a correct vimeo video url`, () => {
|
||||
expect(markdownIt.renderInline(validUrl)).toBe("<app-vimeo id='23237102'></app-vimeo>")
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ describe('Replace youtube link', () => {
|
||||
;['www.', ''].forEach((subdomain) => {
|
||||
;['youtube.com', 'youtube-nocookie.com'].forEach((domain) => {
|
||||
const origin = `${protocol}${subdomain}${domain}/`
|
||||
describe(origin, () => {
|
||||
describe(`Replacer for ${origin}`, () => {
|
||||
const validUrl = `${origin}?v=12312312312`
|
||||
it(`can detect a correct youtube video url`, () => {
|
||||
expect(markdownIt.renderInline(validUrl)).toBe('<app-youtube id="12312312312"></app-youtube>')
|
||||
|
||||
@@ -14,14 +14,14 @@ const handler = (req: NextApiRequest, res: NextApiResponse) => {
|
||||
createdAt: '2022-03-20T20:36:32Z',
|
||||
uuid: '5355ed83-7e12-4db0-95ed-837e124db08c',
|
||||
fileName: 'dummy.png',
|
||||
noteId: 'features'
|
||||
noteAlias: 'features'
|
||||
},
|
||||
{
|
||||
username: 'tilman',
|
||||
createdAt: '2022-03-20T20:36:57+0000',
|
||||
uuid: '656745ab-fbf9-47f1-a745-abfbf9a7f10c',
|
||||
fileName: 'dummy2.png',
|
||||
noteId: null
|
||||
noteAlias: null
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ const handler = async (req: NextApiRequest, res: NextApiResponse): Promise<void>
|
||||
{
|
||||
uuid: 'e81f57cd-5866-4253-9f57-cd5866a253ca',
|
||||
fileName: 'avatar.png',
|
||||
noteId: null,
|
||||
noteAlias: null,
|
||||
username: 'test',
|
||||
createdAt: '2022-02-27T21:54:23.856Z'
|
||||
},
|
||||
|
||||
@@ -40,7 +40,8 @@ const handler = (req: NextApiRequest, res: NextApiResponse): void => {
|
||||
groupName: '_EVERYONE',
|
||||
canEdit: false
|
||||
}
|
||||
]
|
||||
],
|
||||
publiclyVisible: true
|
||||
}
|
||||
},
|
||||
editedByAtPosition: []
|
||||
|
||||
@@ -38,7 +38,8 @@ const handler = (req: NextApiRequest, res: NextApiResponse): void => {
|
||||
groupName: '_LOGGED_IN',
|
||||
canEdit: false
|
||||
}
|
||||
]
|
||||
],
|
||||
publiclyVisible: true
|
||||
}
|
||||
},
|
||||
editedByAtPosition: []
|
||||
|
||||
@@ -47,7 +47,8 @@ const handler = (req: NextApiRequest, res: NextApiResponse): void => {
|
||||
groupName: 'hedgedoc-devs',
|
||||
canEdit: true
|
||||
}
|
||||
]
|
||||
],
|
||||
publiclyVisible: true
|
||||
}
|
||||
},
|
||||
editedByAtPosition: []
|
||||
|
||||
@@ -16,7 +16,8 @@ describe('build state from server permissions', () => {
|
||||
permissions: {
|
||||
owner: null,
|
||||
sharedToGroups: [],
|
||||
sharedToUsers: []
|
||||
sharedToUsers: [],
|
||||
publiclyVisible: false
|
||||
},
|
||||
editedBy: [],
|
||||
primaryAlias: 'test-id',
|
||||
|
||||
+2
-1
@@ -24,7 +24,8 @@ describe('build state from server permissions', () => {
|
||||
groupName: 'test-group',
|
||||
canEdit: false
|
||||
}
|
||||
]
|
||||
],
|
||||
publiclyVisible: false
|
||||
}
|
||||
expect(buildStateFromServerPermissions(state, permissions)).toStrictEqual({ ...state, permissions: permissions })
|
||||
})
|
||||
|
||||
+4
-2
@@ -50,7 +50,8 @@ describe('build state from set note data from server', () => {
|
||||
canEdit: true,
|
||||
username: 'shareusername'
|
||||
}
|
||||
]
|
||||
],
|
||||
publiclyVisible: false
|
||||
},
|
||||
tags: ['tag'],
|
||||
title: 'title',
|
||||
@@ -118,7 +119,8 @@ describe('build state from set note data from server', () => {
|
||||
canEdit: true,
|
||||
username: 'shareusername'
|
||||
}
|
||||
]
|
||||
],
|
||||
publiclyVisible: false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user