mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-15 06:33:55 +01:00
Merge pull request #35739 from overleaf/mfb-bring-main-bibliography-to-top-level
Bring main bibliography file to the top level settings GitOrigin-RevId: 4c4d4927067995d947c6d0656425760ce56f9435
This commit is contained in:
committed by
Copybot
parent
6f8a1be171
commit
02d36687cd
@@ -669,6 +669,24 @@ const EditorController = {
|
||||
)
|
||||
},
|
||||
|
||||
setReferenceFormat(projectId, newReferenceFormat, callback) {
|
||||
ProjectOptionsHandler.setReferenceFormat(
|
||||
projectId,
|
||||
newReferenceFormat,
|
||||
function (err) {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
EditorRealTimeController.emitToRoom(
|
||||
projectId,
|
||||
'referenceFormatUpdated',
|
||||
newReferenceFormat
|
||||
)
|
||||
callback()
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
_notifyProjectUsersOfNewFolders(projectId, folders, callback) {
|
||||
async.eachSeries(
|
||||
folders,
|
||||
@@ -732,5 +750,6 @@ EditorController.promises = {
|
||||
setPublicAccessLevel: promisify(EditorController.setPublicAccessLevel),
|
||||
setRootDoc: promisify(EditorController.setRootDoc),
|
||||
setMainBibliographyDoc: promisify(EditorController.setMainBibliographyDoc),
|
||||
setReferenceFormat: promisify(EditorController.setReferenceFormat),
|
||||
}
|
||||
export default EditorController
|
||||
|
||||
@@ -92,6 +92,7 @@ const updateProjectSettingsSchema = z.object({
|
||||
name: z.string().optional(),
|
||||
rootDocId: zz.objectId().optional(),
|
||||
spellCheckLanguage: z.string().optional(),
|
||||
referenceFormat: z.enum(['bibtex', 'biblatex']).optional(),
|
||||
}),
|
||||
})
|
||||
|
||||
@@ -144,6 +145,13 @@ const _ProjectController = {
|
||||
)
|
||||
}
|
||||
|
||||
if (body.referenceFormat != null) {
|
||||
await EditorController.promises.setReferenceFormat(
|
||||
projectId,
|
||||
body.referenceFormat
|
||||
)
|
||||
}
|
||||
|
||||
res.sendStatus(204)
|
||||
},
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ export default ProjectEditorHandler = {
|
||||
compiler: project.compiler,
|
||||
description: project.description,
|
||||
spellCheckLanguage: project.spellCheckLanguage,
|
||||
referenceFormat: project.referenceFormat,
|
||||
png2pdf: project.png2pdf,
|
||||
deletedByExternalDataSource: project.deletedByExternalDataSource || false,
|
||||
imageName:
|
||||
|
||||
@@ -119,6 +119,15 @@ const ProjectOptionsHandler = {
|
||||
const { otMigrationStage } = project.overleaf.history
|
||||
return { otMigrationStage }
|
||||
},
|
||||
|
||||
async setReferenceFormat(projectId, newReferenceFormat) {
|
||||
if (!newReferenceFormat) {
|
||||
return
|
||||
}
|
||||
const conditions = { _id: projectId }
|
||||
const update = { referenceFormat: newReferenceFormat }
|
||||
return Project.updateOne(conditions, update, {})
|
||||
},
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -135,5 +144,6 @@ export default {
|
||||
setHistoryRangesSupport: callbackify(
|
||||
ProjectOptionsHandler.setHistoryRangesSupport
|
||||
),
|
||||
setReferenceFormat: callbackify(ProjectOptionsHandler.setReferenceFormat),
|
||||
promises: ProjectOptionsHandler,
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ export const ProjectSchema = new Schema(
|
||||
},
|
||||
],
|
||||
deferredTpdsFlushCounter: { type: Number },
|
||||
referenceFormat: { type: String },
|
||||
},
|
||||
{ minimize: false }
|
||||
)
|
||||
|
||||
@@ -214,6 +214,8 @@
|
||||
"beta_program_already_participating": "",
|
||||
"beta_program_benefits": "",
|
||||
"beta_program_not_participating": "",
|
||||
"biblatex": "",
|
||||
"bibtex": "",
|
||||
"bibtex_duplicates_keys": "",
|
||||
"billed_annually_at": "",
|
||||
"billed_monthly_at": "",
|
||||
@@ -1622,6 +1624,7 @@
|
||||
"reference_count": "",
|
||||
"reference_count_plural": "",
|
||||
"reference_error_relink_hint": "",
|
||||
"reference_format": "",
|
||||
"reference_manager_linked": "",
|
||||
"reference_manager_lowercase": "",
|
||||
"reference_manager_searched_groups": "",
|
||||
@@ -1632,6 +1635,7 @@
|
||||
"reference_search_settings": "",
|
||||
"reference_search_style": "",
|
||||
"reference_sync": "",
|
||||
"references": "",
|
||||
"references_from_these_libraries_will_be_included_in_your_reference_search_results": "",
|
||||
"refresh": "",
|
||||
"refresh_page_after_linking_dropbox": "",
|
||||
@@ -1806,7 +1810,6 @@
|
||||
"select_all_projects": "",
|
||||
"select_an_output_file": "",
|
||||
"select_an_output_file_figure_modal": "",
|
||||
"select_bib_file": "",
|
||||
"select_cells_in_a_single_row_to_merge": "",
|
||||
"select_color": "",
|
||||
"select_entry": "",
|
||||
|
||||
@@ -4,7 +4,11 @@ import { PermissionsLevel } from '@/features/ide-react/types/permissions'
|
||||
export type JoinProjectPayloadProject = Pick<
|
||||
Project,
|
||||
Exclude<keyof Project, ['rootDocId', 'publicAccessLevel']>
|
||||
> & { rootDoc_id?: string; publicAccesLevel?: string }
|
||||
> & {
|
||||
rootDoc_id?: string
|
||||
mainBibliographyDoc_id?: string
|
||||
publicAccesLevel?: string
|
||||
}
|
||||
|
||||
export type JoinProjectPayload = {
|
||||
permissionsLevel: PermissionsLevel
|
||||
|
||||
@@ -103,12 +103,18 @@ export const IdeReactProvider: FC<React.PropsWithChildren> = ({ children }) => {
|
||||
function handleJoinProjectResponse({
|
||||
project: {
|
||||
rootDoc_id: rootDocId,
|
||||
mainBibliographyDoc_id: mainBibliographyDocId,
|
||||
publicAccesLevel: publicAccessLevel,
|
||||
..._project
|
||||
},
|
||||
permissionsLevel,
|
||||
}: JoinProjectPayload) {
|
||||
const project = { ..._project, rootDocId, publicAccessLevel }
|
||||
const project = {
|
||||
..._project,
|
||||
rootDocId,
|
||||
mainBibliographyDocId,
|
||||
publicAccessLevel,
|
||||
}
|
||||
|
||||
// Cast the project from the payload as ProjectMetadata to ensure it has
|
||||
// the correct type for the context. It must be close enough because the
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import DropdownSetting from '../dropdown-setting'
|
||||
import { useProjectSettingsContext } from '../../context/project-settings-context'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
|
||||
export default function ReferenceFormatSetting() {
|
||||
const { t } = useTranslation()
|
||||
const { write } = usePermissionsContext()
|
||||
const { referenceFormat, setReferenceFormat } = useProjectSettingsContext()
|
||||
|
||||
return (
|
||||
<DropdownSetting
|
||||
id="referenceFormat"
|
||||
label={t('reference_format')}
|
||||
options={[
|
||||
{
|
||||
value: 'bibtex',
|
||||
label: t('bibtex'),
|
||||
},
|
||||
{
|
||||
value: 'biblatex',
|
||||
label: t('biblatex'),
|
||||
},
|
||||
]}
|
||||
onChange={setReferenceFormat}
|
||||
value={referenceFormat || 'biblatex'}
|
||||
translateOptions="no"
|
||||
disabled={!write}
|
||||
/>
|
||||
)
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
|
||||
import { useMemo } from 'react'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
import DropdownSetting from '../dropdown-setting'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useBibliographyDocId } from '../../hooks/use-bibliography-doc-id'
|
||||
|
||||
export default function RootBibDocumentSetting() {
|
||||
const { docs } = useFileTreeData()
|
||||
const { write } = usePermissionsContext()
|
||||
const { t } = useTranslation()
|
||||
const { setMainBibliographyDocId, mainBibliographyDocId } =
|
||||
useBibliographyDocId()
|
||||
|
||||
const validDocsOptions = useMemo(() => {
|
||||
return docs
|
||||
?.filter(doc => doc.doc.name.toLowerCase().endsWith('.bib'))
|
||||
.map(doc => ({ value: doc.doc.id, label: doc.path }))
|
||||
}, [docs])
|
||||
|
||||
return (
|
||||
<DropdownSetting
|
||||
id="mainBibliographyDocId"
|
||||
label={t('main_bibliography_file_for_this_project')}
|
||||
description={`${t(
|
||||
'this_is_the_file_that_references_pulled_from_your_reference_manager_will_be_added_to'
|
||||
)}`}
|
||||
disabled={!write || !validDocsOptions?.length}
|
||||
options={validDocsOptions ?? []}
|
||||
onChange={setMainBibliographyDocId}
|
||||
value={mainBibliographyDocId ?? ''}
|
||||
translateOptions="no"
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -13,6 +13,9 @@ type ProjectSettingsSetterContextValue = {
|
||||
setSpellCheckLanguage: (
|
||||
spellCheckLanguage: ProjectSettings['spellCheckLanguage']
|
||||
) => void
|
||||
setReferenceFormat: (
|
||||
referenceFormat: ProjectSettings['referenceFormat']
|
||||
) => Promise<void>
|
||||
setAutoComplete: (autoComplete: UserSettings['autoComplete']) => void
|
||||
setAutoPairDelimiters: (
|
||||
autoPairDelimiters: UserSettings['autoPairDelimiters']
|
||||
@@ -67,6 +70,8 @@ export const ProjectSettingsProvider: FC<React.PropsWithChildren> = ({
|
||||
setRootDocId,
|
||||
spellCheckLanguage,
|
||||
setSpellCheckLanguage,
|
||||
referenceFormat,
|
||||
setReferenceFormat,
|
||||
} = useProjectWideSettings()
|
||||
|
||||
const {
|
||||
@@ -174,6 +179,8 @@ export const ProjectSettingsProvider: FC<React.PropsWithChildren> = ({
|
||||
setMendeley,
|
||||
papers,
|
||||
setPapers,
|
||||
referenceFormat,
|
||||
setReferenceFormat,
|
||||
}),
|
||||
[
|
||||
compiler,
|
||||
@@ -230,6 +237,8 @@ export const ProjectSettingsProvider: FC<React.PropsWithChildren> = ({
|
||||
setMendeley,
|
||||
papers,
|
||||
setPapers,
|
||||
referenceFormat,
|
||||
setReferenceFormat,
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ import FontSizeSetting from '@/features/ide-settings/components/appearance-setti
|
||||
import LineHeightSetting from '@/features/ide-settings/components/appearance-settings/line-height-setting'
|
||||
import FontFamilySetting from '@/features/ide-settings/components/appearance-settings/font-family-setting'
|
||||
import DarkModePdfSetting from '@/features/ide-settings/components/appearance-settings/dark-mode-pdf-setting'
|
||||
import RootBibDocumentSetting from '../components/reference-settings/root-bib-document-setting'
|
||||
import ReferenceFormatSetting from '../components/reference-settings/reference-format-setting'
|
||||
|
||||
import { useProjectSettingsContext } from '@/features/ide-settings/context/project-settings-context'
|
||||
import { useFeatureFlag } from '@/shared/context/split-test-context'
|
||||
@@ -149,11 +151,6 @@ export const SettingsModalProvider: FC<React.PropsWithChildren> = ({
|
||||
key: 'pdfViewer',
|
||||
component: <PDFViewerSetting />,
|
||||
},
|
||||
{
|
||||
key: 'write-and-cite-settings',
|
||||
component: <ReferenceSearchSetting />,
|
||||
hidden: !ReferenceSearchSetting,
|
||||
},
|
||||
{
|
||||
key: 'floating-menu',
|
||||
component: <FloatingMenuSetting />,
|
||||
@@ -236,6 +233,31 @@ export const SettingsModalProvider: FC<React.PropsWithChildren> = ({
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'references',
|
||||
title: t('references'),
|
||||
icon: 'book_5',
|
||||
sections: [
|
||||
{
|
||||
key: 'general',
|
||||
settings: [
|
||||
{
|
||||
key: 'mainBibliographyDocId',
|
||||
component: <RootBibDocumentSetting />,
|
||||
},
|
||||
{
|
||||
key: 'referenceFormat',
|
||||
component: <ReferenceFormatSetting />,
|
||||
},
|
||||
{
|
||||
key: 'write-and-cite-settings',
|
||||
component: <ReferenceSearchSetting />,
|
||||
hidden: !ReferenceSearchSetting,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'appearance',
|
||||
title: t('appearance'),
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useProjectContext } from '@/shared/context/project-context'
|
||||
import type { ProjectSettings } from '../utils/api'
|
||||
import useSaveProjectSettings from './use-save-project-settings'
|
||||
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
|
||||
|
||||
export const useBibliographyDocId = () => {
|
||||
const { project } = useProjectContext()
|
||||
const mainBibliographyDocId = project?.mainBibliographyDocId
|
||||
const saveProjectSettings = useSaveProjectSettings()
|
||||
const { write } = usePermissionsContext()
|
||||
|
||||
const setMainBibliographyDocIdFunc = useCallback(
|
||||
async (
|
||||
newMainBibliographyDocId: ProjectSettings['mainBibliographyDocId']
|
||||
) => {
|
||||
if (write) {
|
||||
try {
|
||||
await saveProjectSettings(
|
||||
'mainBibliographyDocId',
|
||||
newMainBibliographyDocId
|
||||
)
|
||||
} catch (err) {
|
||||
// TODO: retry mechanism (max 10x before failed completely and rollback the old value)
|
||||
}
|
||||
}
|
||||
},
|
||||
[write, saveProjectSettings]
|
||||
)
|
||||
|
||||
return {
|
||||
mainBibliographyDocId,
|
||||
setMainBibliographyDocId: setMainBibliographyDocIdFunc,
|
||||
}
|
||||
}
|
||||
+12
@@ -44,6 +44,15 @@ export default function useProjectWideSettingsSocketListener() {
|
||||
[project, updateProject]
|
||||
)
|
||||
|
||||
const setReferenceFormat = useCallback(
|
||||
(referenceFormat: ProjectSettings['referenceFormat']) => {
|
||||
if (project) {
|
||||
updateProject({ referenceFormat })
|
||||
}
|
||||
},
|
||||
[project, updateProject]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
// data is not available on initial mounting
|
||||
const dataAvailable = !!project
|
||||
@@ -53,6 +62,7 @@ export default function useProjectWideSettingsSocketListener() {
|
||||
socket.on('imageNameUpdated', setImageName)
|
||||
socket.on('png2pdfUpdated', setPng2pdf)
|
||||
socket.on('spellCheckLanguageUpdated', setSpellCheckLanguage)
|
||||
socket.on('referenceFormatUpdated', setReferenceFormat)
|
||||
return () => {
|
||||
socket.removeListener('compilerUpdated', setCompiler)
|
||||
socket.removeListener('imageNameUpdated', setImageName)
|
||||
@@ -61,6 +71,7 @@ export default function useProjectWideSettingsSocketListener() {
|
||||
'spellCheckLanguageUpdated',
|
||||
setSpellCheckLanguage
|
||||
)
|
||||
socket.removeListener('referenceFormatUpdated', setReferenceFormat)
|
||||
}
|
||||
}
|
||||
}, [
|
||||
@@ -68,6 +79,7 @@ export default function useProjectWideSettingsSocketListener() {
|
||||
project,
|
||||
setCompiler,
|
||||
setImageName,
|
||||
setReferenceFormat,
|
||||
setPng2pdf,
|
||||
setSpellCheckLanguage,
|
||||
])
|
||||
|
||||
@@ -31,6 +31,15 @@ export default function useProjectWideSettings() {
|
||||
[saveProjectSettings]
|
||||
)
|
||||
|
||||
const setReferenceFormat = useCallback(
|
||||
async (newReferenceFormat: ProjectSettings['referenceFormat']) => {
|
||||
await saveProjectSettings('referenceFormat', newReferenceFormat).catch(
|
||||
debugConsole.error
|
||||
)
|
||||
},
|
||||
[saveProjectSettings]
|
||||
)
|
||||
|
||||
const setPng2pdf = useCallback(
|
||||
async (newPng2pdf: ProjectSettings['png2pdf']) => {
|
||||
await saveProjectSettings('png2pdf', newPng2pdf).catch(debugConsole.error)
|
||||
@@ -46,6 +55,8 @@ export default function useProjectWideSettings() {
|
||||
setCompiler,
|
||||
imageName: project?.imageName,
|
||||
setImageName,
|
||||
referenceFormat: project?.referenceFormat,
|
||||
setReferenceFormat,
|
||||
png2pdf: project?.png2pdf ?? png2pdfEnabled,
|
||||
setPng2pdf,
|
||||
rootDocId,
|
||||
|
||||
@@ -13,6 +13,8 @@ export interface ProjectSettings {
|
||||
rootDocId: string
|
||||
spellCheckLanguage: string
|
||||
name: string
|
||||
mainBibliographyDocId?: string
|
||||
referenceFormat?: 'bibtex' | 'biblatex'
|
||||
}
|
||||
|
||||
type SaveUserSettings = Partial<
|
||||
|
||||
@@ -50,7 +50,6 @@ export type MyAccessRequest = Pick<
|
||||
|
||||
export interface ProjectMetadata extends ProjectSettings {
|
||||
_id: string
|
||||
mainBibliographyDocId?: string
|
||||
members: ProjectMember[]
|
||||
invites: ProjectMember[]
|
||||
editAccessRequests?: EditAccessRequest[]
|
||||
|
||||
@@ -1566,7 +1566,6 @@
|
||||
"select_all_projects": "Vælg alle projekter",
|
||||
"select_an_output_file": "Vælg en outputfil",
|
||||
"select_an_output_file_figure_modal": "Vælg en outputfil",
|
||||
"select_bib_file": "Vælg .bib fil",
|
||||
"select_cells_in_a_single_row_to_merge": "Vælg celler i en enkelt række at flette",
|
||||
"select_color": "Vælg farven __name__",
|
||||
"select_folder_from_project": "Vælg mappe fra projekt",
|
||||
|
||||
@@ -283,7 +283,9 @@
|
||||
"beta_program_not_participating": "You are not enrolled in the beta program",
|
||||
"beta_program_opt_in_action": "Opt-in to beta program",
|
||||
"beta_program_opt_out_action": "Opt-out of beta program",
|
||||
"biblatex": "BibLaTeX",
|
||||
"bibliographies": "Bibliographies",
|
||||
"bibtex": "BibTeX",
|
||||
"bibtex_duplicates_keys": "The file __fileName__ contains more than one entry with the citation key __key__. Only the first occurrence is shown in this list.",
|
||||
"billed_annually_at": "Billed annually at <0>__price__</0> <1>(includes plan and any add-ons)</1>",
|
||||
"billed_monthly_at": "Billed monthly at <0>__price__</0> <1>(includes plan and any add-ons)</1>",
|
||||
@@ -2116,6 +2118,7 @@
|
||||
"reference_count": "__count__ reference",
|
||||
"reference_count_plural": "__count__ references",
|
||||
"reference_error_relink_hint": "If this error persists, try re-linking your account here:",
|
||||
"reference_format": "Reference format",
|
||||
"reference_manager_linked": "Reference manager linked",
|
||||
"reference_manager_lowercase": "reference manager",
|
||||
"reference_manager_searched_groups": "__provider__ search groups",
|
||||
@@ -2127,6 +2130,7 @@
|
||||
"reference_search_settings": "Reference search settings",
|
||||
"reference_search_style": "Reference search style",
|
||||
"reference_sync": "Reference manager sync",
|
||||
"references": "References",
|
||||
"references_from_these_libraries_will_be_included_in_your_reference_search_results": "References from these libraries will be included in your reference search results.",
|
||||
"refresh": "Refresh",
|
||||
"refresh_page_after_linking_dropbox": "Please refresh this page after linking your account to Dropbox.",
|
||||
@@ -2340,7 +2344,6 @@
|
||||
"select_all_projects": "Select all projects",
|
||||
"select_an_output_file": "Select an Output File",
|
||||
"select_an_output_file_figure_modal": "Select an output file",
|
||||
"select_bib_file": "Select .bib file",
|
||||
"select_cells_in_a_single_row_to_merge": "Select cells in a single row to merge",
|
||||
"select_color": "Select color __name__",
|
||||
"select_entry": "Select entry",
|
||||
@@ -2729,7 +2732,7 @@
|
||||
"this_could_be_because_we_cant_support_some_elements_of_the_table": "This could be because we can’t yet support some elements of the table in the table preview. Or there may be an error in the table’s LaTeX code.",
|
||||
"this_field_is_required": "This field is required",
|
||||
"this_grants_access_to_features_2": "This grants you access to <0>__appName__</0> <0>__featureType__</0> features.",
|
||||
"this_is_the_file_that_references_pulled_from_your_reference_manager_will_be_added_to": "This is the file that references pulled from your reference manager will be added to.",
|
||||
"this_is_the_file_that_references_pulled_from_your_reference_manager_will_be_added_to": "New references are saved to the .bib file you select here. If your project doesn’t have one yet, add a .bib file to choose it.",
|
||||
"this_is_your_template": "This is your template from your project",
|
||||
"this_organization_is_tax_exempt": "This organization is tax exempt",
|
||||
"this_policy_applies_to_all_projects_owned_by_your_group_members": "This policy applies to all projects owned by your group members. Project owners can apply stricter sharing rules for individual projects.",
|
||||
|
||||
@@ -1782,7 +1782,6 @@
|
||||
"select_all_projects": "全选",
|
||||
"select_an_output_file": "选择输出文件",
|
||||
"select_an_output_file_figure_modal": "选择一个输出文件",
|
||||
"select_bib_file": "选择 .bib 文件",
|
||||
"select_cells_in_a_single_row_to_merge": "在一行中选择单元格合并",
|
||||
"select_color": "选择颜色 __name__",
|
||||
"select_folder_from_project": "从项目中选择文件夹",
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
import { screen, within, render } from '@testing-library/react'
|
||||
import { expect } from 'chai'
|
||||
import fetchMock from 'fetch-mock'
|
||||
import { SettingsModalProvider } from '@/features/ide-settings/context/settings-modal-context'
|
||||
import {
|
||||
EditorProviders,
|
||||
projectDefaults,
|
||||
} from '../../../helpers/editor-providers'
|
||||
import ReferenceFormatSetting from '@/features/ide-settings/components/reference-settings/reference-format-setting'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
|
||||
// bibtex is listed first as it differs from the component's default
|
||||
// ('biblatex'), so selecting it is guaranteed to trigger a change.
|
||||
const OPTIONS = [
|
||||
{
|
||||
label: 'BibTeX',
|
||||
value: 'bibtex',
|
||||
},
|
||||
{
|
||||
label: 'BibLaTeX',
|
||||
value: 'biblatex',
|
||||
},
|
||||
]
|
||||
|
||||
describe('<ReferenceFormatSetting />', function () {
|
||||
afterEach(function () {
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
})
|
||||
|
||||
it('defaults to BibLaTeX', function () {
|
||||
render(
|
||||
<EditorProviders>
|
||||
<SettingsModalProvider>
|
||||
<ReferenceFormatSetting />
|
||||
</SettingsModalProvider>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
const select = screen.getByLabelText(
|
||||
'Reference format'
|
||||
) as HTMLSelectElement
|
||||
expect(select.value).to.equal('biblatex')
|
||||
})
|
||||
|
||||
it('each option is shown and can be selected', async function () {
|
||||
render(
|
||||
<EditorProviders>
|
||||
<SettingsModalProvider>
|
||||
<ReferenceFormatSetting />
|
||||
</SettingsModalProvider>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
const saveSettingsMock = fetchMock.post(
|
||||
`express:/project/:projectId/settings`,
|
||||
{
|
||||
status: 200,
|
||||
},
|
||||
{ delay: 0 }
|
||||
)
|
||||
|
||||
const select = screen.getByLabelText('Reference format')
|
||||
|
||||
for (const option of OPTIONS) {
|
||||
const optionElement = within(select).getByText(option.label)
|
||||
expect(optionElement.getAttribute('value')).to.equal(option.value)
|
||||
await userEvent.selectOptions(select, [optionElement])
|
||||
|
||||
expect(
|
||||
saveSettingsMock.callHistory.called(
|
||||
`/project/${projectDefaults._id}/settings`,
|
||||
{
|
||||
body: { referenceFormat: option.value },
|
||||
}
|
||||
)
|
||||
).to.be.true
|
||||
}
|
||||
})
|
||||
})
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
import { screen, within, render } from '@testing-library/react'
|
||||
import { expect } from 'chai'
|
||||
import fetchMock from 'fetch-mock'
|
||||
import { Folder } from '../../../../../types/folder'
|
||||
import { SettingsModalProvider } from '@/features/ide-settings/context/settings-modal-context'
|
||||
import {
|
||||
EditorProviders,
|
||||
projectDefaults,
|
||||
} from '../../../helpers/editor-providers'
|
||||
import RootBibDocumentSetting from '@/features/ide-settings/components/reference-settings/root-bib-document-setting'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
|
||||
const OPTIONS = [
|
||||
{
|
||||
label: 'main.bib',
|
||||
value: '123abc',
|
||||
},
|
||||
{
|
||||
label: 'another.bib',
|
||||
value: '123abcd',
|
||||
},
|
||||
]
|
||||
|
||||
describe('<RootBibDocumentSetting />', function () {
|
||||
const rootFolder: Folder = {
|
||||
_id: 'root-folder-id',
|
||||
name: 'rootFolder',
|
||||
docs: [
|
||||
{
|
||||
_id: '123abc',
|
||||
name: 'main.bib',
|
||||
},
|
||||
{
|
||||
_id: '123abcd',
|
||||
name: 'another.bib',
|
||||
},
|
||||
{
|
||||
_id: '123abce',
|
||||
name: 'main.tex',
|
||||
},
|
||||
],
|
||||
fileRefs: [],
|
||||
folders: [],
|
||||
}
|
||||
|
||||
afterEach(function () {
|
||||
fetchMock.removeRoutes().clearHistory()
|
||||
})
|
||||
|
||||
it('only lists .bib files as options', function () {
|
||||
render(
|
||||
<EditorProviders rootFolder={[rootFolder as any]}>
|
||||
<SettingsModalProvider>
|
||||
<RootBibDocumentSetting />
|
||||
</SettingsModalProvider>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
const select = screen.getByLabelText(
|
||||
'Main bibliography file for this project'
|
||||
)
|
||||
|
||||
expect(within(select).getByText('main.bib')).to.exist
|
||||
expect(within(select).getByText('another.bib')).to.exist
|
||||
expect(within(select).queryByText('main.tex')).to.be.null
|
||||
})
|
||||
|
||||
it('each option is shown and can be selected', async function () {
|
||||
render(
|
||||
<EditorProviders rootFolder={[rootFolder as any]}>
|
||||
<SettingsModalProvider>
|
||||
<RootBibDocumentSetting />
|
||||
</SettingsModalProvider>
|
||||
</EditorProviders>
|
||||
)
|
||||
|
||||
const saveSettingsMock = fetchMock.post(
|
||||
`express:/project/:projectId/settings`,
|
||||
{
|
||||
status: 200,
|
||||
},
|
||||
{ delay: 0 }
|
||||
)
|
||||
|
||||
const select = screen.getByLabelText(
|
||||
'Main bibliography file for this project'
|
||||
)
|
||||
|
||||
// Reverse order so we test changing to each option
|
||||
for (const option of [...OPTIONS].reverse()) {
|
||||
const optionElement = within(select).getByText(option.label)
|
||||
expect(optionElement.getAttribute('value')).to.equal(option.value)
|
||||
await userEvent.selectOptions(select, [optionElement])
|
||||
|
||||
expect(
|
||||
saveSettingsMock.callHistory.called(
|
||||
`/project/${projectDefaults._id}/settings`,
|
||||
{
|
||||
body: { mainBibliographyDocId: option.value },
|
||||
}
|
||||
)
|
||||
).to.be.true
|
||||
}
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user