mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[web] Personal Access Token Settings UI (#13040)
* [web] Personal Access Token Settings UI * [web] Add Personal Access Token Settings UI to settings page * [web] Added `personal-access-token-settings` unit tests GitOrigin-RevId: 353b2f1a2b57c3292554f129be6cbb4f8f8382f8
This commit is contained in:
parent
db9e17bd47
commit
27c2d1c16e
15 changed files with 180 additions and 6 deletions
|
@ -68,6 +68,18 @@ async function settingsPage(req, res) {
|
||||||
|
|
||||||
const showPersonalAccessToken =
|
const showPersonalAccessToken =
|
||||||
!Features.hasFeature('saas') || req.query?.personal_access_token === 'true'
|
!Features.hasFeature('saas') || req.query?.personal_access_token === 'true'
|
||||||
|
let personalAccessTokens
|
||||||
|
if (showPersonalAccessToken) {
|
||||||
|
try {
|
||||||
|
// require this here because module may not be included in some versions
|
||||||
|
const PersonalAccessTokenManager = require('../../../../modules/oauth2-server/app/src/OAuthPersonalAccessTokenManager')
|
||||||
|
personalAccessTokens = await PersonalAccessTokenManager.listTokens(
|
||||||
|
user._id
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(OError.tag(error))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res.render('user/settings', {
|
res.render('user/settings', {
|
||||||
title: 'account_settings',
|
title: 'account_settings',
|
||||||
|
@ -112,6 +124,7 @@ async function settingsPage(req, res) {
|
||||||
thirdPartyIds: UserPagesController._restructureThirdPartyIds(user),
|
thirdPartyIds: UserPagesController._restructureThirdPartyIds(user),
|
||||||
projectSyncSuccessMessage,
|
projectSyncSuccessMessage,
|
||||||
showPersonalAccessToken,
|
showPersonalAccessToken,
|
||||||
|
personalAccessTokens,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ block append meta
|
||||||
meta(name="ol-github" data-type="json" content=github)
|
meta(name="ol-github" data-type="json" content=github)
|
||||||
meta(name="ol-projectSyncSuccessMessage", content=projectSyncSuccessMessage)
|
meta(name="ol-projectSyncSuccessMessage", content=projectSyncSuccessMessage)
|
||||||
meta(name="ol-showPersonalAccessToken", data-type="boolean" content=showPersonalAccessToken)
|
meta(name="ol-showPersonalAccessToken", data-type="boolean" content=showPersonalAccessToken)
|
||||||
|
meta(name="ol-personalAccessTokens", data-type="json" content=personalAccessTokens)
|
||||||
|
|
||||||
block content
|
block content
|
||||||
main.content.content-alt#settings-page-root
|
main.content.content-alt#settings-page-root
|
||||||
|
|
|
@ -805,6 +805,7 @@ module.exports = {
|
||||||
importProjectFromGithubMenu: [],
|
importProjectFromGithubMenu: [],
|
||||||
editorLeftMenuSync: [],
|
editorLeftMenuSync: [],
|
||||||
editorLeftMenuManageTemplate: [],
|
editorLeftMenuManageTemplate: [],
|
||||||
|
oauth2Server: [],
|
||||||
},
|
},
|
||||||
|
|
||||||
moduleImportSequence: [
|
moduleImportSequence: [
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
"add_affiliation": "",
|
"add_affiliation": "",
|
||||||
"add_another_address_line": "",
|
"add_another_address_line": "",
|
||||||
"add_another_email": "",
|
"add_another_email": "",
|
||||||
|
"add_another_token": "",
|
||||||
"add_comma_separated_emails_help": "",
|
"add_comma_separated_emails_help": "",
|
||||||
"add_company_details": "",
|
"add_company_details": "",
|
||||||
"add_email_to_claim_features": "",
|
"add_email_to_claim_features": "",
|
||||||
|
@ -155,6 +156,7 @@
|
||||||
"contact_support_to_change_group_subscription": "",
|
"contact_support_to_change_group_subscription": "",
|
||||||
"contact_us": "",
|
"contact_us": "",
|
||||||
"continue_github_merge": "",
|
"continue_github_merge": "",
|
||||||
|
"copied": "",
|
||||||
"copy": "",
|
"copy": "",
|
||||||
"copy_project": "",
|
"copy_project": "",
|
||||||
"copying": "",
|
"copying": "",
|
||||||
|
@ -168,6 +170,7 @@
|
||||||
"create_new_subscription": "",
|
"create_new_subscription": "",
|
||||||
"create_new_tag": "",
|
"create_new_tag": "",
|
||||||
"create_project_in_github": "",
|
"create_project_in_github": "",
|
||||||
|
"created": "",
|
||||||
"created_at": "",
|
"created_at": "",
|
||||||
"creating": "",
|
"creating": "",
|
||||||
"current_password": "",
|
"current_password": "",
|
||||||
|
@ -184,9 +187,12 @@
|
||||||
"delete_acct_no_existing_pw": "",
|
"delete_acct_no_existing_pw": "",
|
||||||
"delete_and_leave": "",
|
"delete_and_leave": "",
|
||||||
"delete_and_leave_projects": "",
|
"delete_and_leave_projects": "",
|
||||||
|
"delete_authentication_token": "",
|
||||||
|
"delete_authentication_token_info": "",
|
||||||
"delete_figure": "",
|
"delete_figure": "",
|
||||||
"delete_projects": "",
|
"delete_projects": "",
|
||||||
"delete_tag": "",
|
"delete_tag": "",
|
||||||
|
"delete_token": "",
|
||||||
"delete_your_account": "",
|
"delete_your_account": "",
|
||||||
"deleted_at": "",
|
"deleted_at": "",
|
||||||
"deleting": "",
|
"deleting": "",
|
||||||
|
@ -259,6 +265,8 @@
|
||||||
"example_project": "",
|
"example_project": "",
|
||||||
"existing_plan_active_until_term_end": "",
|
"existing_plan_active_until_term_end": "",
|
||||||
"expand": "",
|
"expand": "",
|
||||||
|
"expired": "",
|
||||||
|
"expires": "",
|
||||||
"export_csv": "",
|
"export_csv": "",
|
||||||
"export_project_to_github": "",
|
"export_project_to_github": "",
|
||||||
"fast": "",
|
"fast": "",
|
||||||
|
@ -329,6 +337,7 @@
|
||||||
"galileo_suggestion_feedback_button": "",
|
"galileo_suggestion_feedback_button": "",
|
||||||
"galileo_suggestions_loading_error": "",
|
"galileo_suggestions_loading_error": "",
|
||||||
"galileo_toggle_description": "",
|
"galileo_toggle_description": "",
|
||||||
|
"generate_token": "",
|
||||||
"generic_if_problem_continues_contact_us": "",
|
"generic_if_problem_continues_contact_us": "",
|
||||||
"generic_linked_file_compile_error": "",
|
"generic_linked_file_compile_error": "",
|
||||||
"generic_something_went_wrong": "",
|
"generic_something_went_wrong": "",
|
||||||
|
@ -337,7 +346,12 @@
|
||||||
"get_most_subscription_by_checking_features": "",
|
"get_most_subscription_by_checking_features": "",
|
||||||
"get_most_subscription_by_checking_premium_features": "",
|
"get_most_subscription_by_checking_premium_features": "",
|
||||||
"git": "",
|
"git": "",
|
||||||
|
"git_authentication_token": "",
|
||||||
|
"git_authentication_token_create_modal_info_1": "",
|
||||||
|
"git_authentication_token_create_modal_info_2": "",
|
||||||
"git_bridge_modal_description": "",
|
"git_bridge_modal_description": "",
|
||||||
|
"git_integration": "",
|
||||||
|
"git_integration_info": "",
|
||||||
"github_commit_message_placeholder": "",
|
"github_commit_message_placeholder": "",
|
||||||
"github_credentials_expired": "",
|
"github_credentials_expired": "",
|
||||||
"github_file_name_error": "",
|
"github_file_name_error": "",
|
||||||
|
@ -477,6 +491,7 @@
|
||||||
"last_name": "",
|
"last_name": "",
|
||||||
"last_resort_trouble_shooting_guide": "",
|
"last_resort_trouble_shooting_guide": "",
|
||||||
"last_updated_date_by_x": "",
|
"last_updated_date_by_x": "",
|
||||||
|
"last_used": "",
|
||||||
"latex_help_guide": "",
|
"latex_help_guide": "",
|
||||||
"latex_places_figures_according_to_a_special_algorithm": "",
|
"latex_places_figures_according_to_a_special_algorithm": "",
|
||||||
"layout": "",
|
"layout": "",
|
||||||
|
@ -933,6 +948,8 @@
|
||||||
"to_change_access_permissions": "",
|
"to_change_access_permissions": "",
|
||||||
"to_modify_your_subscription_go_to": "",
|
"to_modify_your_subscription_go_to": "",
|
||||||
"toggle_compile_options_menu": "",
|
"toggle_compile_options_menu": "",
|
||||||
|
"token": "",
|
||||||
|
"token_limit_reached": "",
|
||||||
"token_read_only": "",
|
"token_read_only": "",
|
||||||
"token_read_write": "",
|
"token_read_write": "",
|
||||||
"too_many_attempts": "",
|
"too_many_attempts": "",
|
||||||
|
@ -1071,6 +1088,13 @@
|
||||||
"you_have_added_x_of_group_size_y": "",
|
"you_have_added_x_of_group_size_y": "",
|
||||||
"your_affiliation_is_confirmed": "",
|
"your_affiliation_is_confirmed": "",
|
||||||
"your_browser_does_not_support_this_feature": "",
|
"your_browser_does_not_support_this_feature": "",
|
||||||
|
"your_git_access_info": "",
|
||||||
|
"your_git_access_info_bullet_1": "",
|
||||||
|
"your_git_access_info_bullet_2": "",
|
||||||
|
"your_git_access_info_bullet_3": "",
|
||||||
|
"your_git_access_info_bullet_4": "",
|
||||||
|
"your_git_access_info_bullet_5": "",
|
||||||
|
"your_git_access_tokens": "",
|
||||||
"your_message_to_collaborators": "",
|
"your_message_to_collaborators": "",
|
||||||
"your_new_plan": "",
|
"your_new_plan": "",
|
||||||
"your_plan": "",
|
"your_plan": "",
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { useState } from 'react'
|
import { useState, ElementType } from 'react'
|
||||||
import { Alert } from 'react-bootstrap'
|
import { Alert } from 'react-bootstrap'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
import importOverleafModules from '../../../../macros/import-overleaf-module.macro'
|
||||||
|
@ -24,7 +24,20 @@ function LinkingSection() {
|
||||||
importOverleafModules('referenceLinkingWidgets')
|
importOverleafModules('referenceLinkingWidgets')
|
||||||
)
|
)
|
||||||
|
|
||||||
const hasIntegrationLinkingSection = integrationLinkingWidgets.length
|
const oauth2ServerComponents = importOverleafModules('oauth2Server') as {
|
||||||
|
import: { default: ElementType }
|
||||||
|
path: string
|
||||||
|
}[]
|
||||||
|
|
||||||
|
const showPersonalAccessToken = getMeta(
|
||||||
|
'ol-showPersonalAccessToken'
|
||||||
|
) as boolean
|
||||||
|
|
||||||
|
const allIntegrationLinkingWidgets = showPersonalAccessToken
|
||||||
|
? integrationLinkingWidgets.concat(oauth2ServerComponents)
|
||||||
|
: integrationLinkingWidgets
|
||||||
|
|
||||||
|
const hasIntegrationLinkingSection = allIntegrationLinkingWidgets.length
|
||||||
const hasReferencesLinkingSection = referenceLinkingWidgets.length
|
const hasReferencesLinkingSection = referenceLinkingWidgets.length
|
||||||
const hasSSOLinkingSection = Object.keys(subscriptions).length > 0
|
const hasSSOLinkingSection = Object.keys(subscriptions).length > 0
|
||||||
|
|
||||||
|
@ -49,12 +62,14 @@ function LinkingSection() {
|
||||||
<Alert bsStyle="success">{projectSyncSuccessMessage}</Alert>
|
<Alert bsStyle="success">{projectSyncSuccessMessage}</Alert>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="settings-widgets-container">
|
<div className="settings-widgets-container">
|
||||||
{integrationLinkingWidgets.map(
|
{allIntegrationLinkingWidgets.map(
|
||||||
({ import: importObject, path }, widgetIndex) => (
|
({ import: importObject, path }, widgetIndex) => (
|
||||||
<ModuleLinkingWidget
|
<ModuleLinkingWidget
|
||||||
key={Object.keys(importObject)[0]}
|
key={Object.keys(importObject)[0]}
|
||||||
ModuleComponent={Object.values(importObject)[0]}
|
ModuleComponent={Object.values(importObject)[0]}
|
||||||
isLast={widgetIndex === integrationLinkingWidgets.length - 1}
|
isLast={
|
||||||
|
widgetIndex === allIntegrationLinkingWidgets.length - 1
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
32
services/web/frontend/js/shared/svgs/git-bridge-logo.js
Normal file
32
services/web/frontend/js/shared/svgs/git-bridge-logo.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -21,7 +21,7 @@ const initialize = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const project: Project = {
|
const project: Project = {
|
||||||
_id: 'a-project',
|
_id: '63e21c07946dd8c76505f85a',
|
||||||
name: 'A Project',
|
name: 'A Project',
|
||||||
features: { mendeley: true, zotero: true },
|
features: { mendeley: true, zotero: true },
|
||||||
tokens: {},
|
tokens: {},
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Project } from '../../../types/project'
|
import { Project } from '../../../types/project'
|
||||||
|
|
||||||
export const project: Project = {
|
export const project: Project = {
|
||||||
_id: 'a-project',
|
_id: '63e21c07946dd8c76505f85a',
|
||||||
name: 'A Project',
|
name: 'A Project',
|
||||||
features: {
|
features: {
|
||||||
collaborators: -1, // unlimited
|
collaborators: -1, // unlimited
|
||||||
|
|
|
@ -60,3 +60,27 @@ export function setDefaultMeta() {
|
||||||
window.metaAttributesCache.delete('referenceLinkingWidgets')
|
window.metaAttributesCache.delete('referenceLinkingWidgets')
|
||||||
window.metaAttributesCache.delete('ol-ssoErrorMessage')
|
window.metaAttributesCache.delete('ol-ssoErrorMessage')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function setPersonalAccessTokensMeta() {
|
||||||
|
function generateToken(_id) {
|
||||||
|
const oneYearFromNow = new Date()
|
||||||
|
oneYearFromNow.setFullYear(oneYearFromNow.getFullYear() + 1)
|
||||||
|
|
||||||
|
const tokenHasBeenUsed = Math.random() > 0.5
|
||||||
|
|
||||||
|
return {
|
||||||
|
_id,
|
||||||
|
accessTokenPartial: 'olp_abc' + _id,
|
||||||
|
createdAt: new Date(),
|
||||||
|
accessTokenExpiresAt: oneYearFromNow,
|
||||||
|
lastUsedAt: tokenHasBeenUsed ? new Date() : undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const tokens = []
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
tokens.push(generateToken(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
window.metaAttributesCache.set('ol-personalAccessTokens', tokens)
|
||||||
|
window.metaAttributesCache.set('ol-showPersonalAccessToken', true)
|
||||||
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {
|
||||||
import {
|
import {
|
||||||
setDefaultMeta as setDefaultLinkingMeta,
|
setDefaultMeta as setDefaultLinkingMeta,
|
||||||
defaultSetupMocks as defaultSetupLinkingMocks,
|
defaultSetupMocks as defaultSetupLinkingMocks,
|
||||||
|
setPersonalAccessTokensMeta,
|
||||||
} from './helpers/linking'
|
} from './helpers/linking'
|
||||||
import { UserProvider } from '../../js/shared/context/user-context'
|
import { UserProvider } from '../../js/shared/context/user-context'
|
||||||
import { ScopeDecorator } from '../decorators/scope'
|
import { ScopeDecorator } from '../decorators/scope'
|
||||||
|
@ -44,9 +45,15 @@ export const Overleaf = args => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const OverleafWithAccessTokens = args => {
|
||||||
|
setPersonalAccessTokensMeta()
|
||||||
|
return Overleaf(args)
|
||||||
|
}
|
||||||
|
|
||||||
export const ServerPro = args => {
|
export const ServerPro = args => {
|
||||||
setDefaultAccountInfoMeta()
|
setDefaultAccountInfoMeta()
|
||||||
setDefaultPasswordMeta()
|
setDefaultPasswordMeta()
|
||||||
|
setPersonalAccessTokensMeta()
|
||||||
useFetchMock(fetchMock => {
|
useFetchMock(fetchMock => {
|
||||||
defaultSetupAccountInfoMocks(fetchMock)
|
defaultSetupAccountInfoMocks(fetchMock)
|
||||||
defaultSetupPasswordMocks(fetchMock)
|
defaultSetupPasswordMocks(fetchMock)
|
||||||
|
|
|
@ -216,3 +216,20 @@ tbody > tr.affiliations-table-warning-row > td {
|
||||||
.setting-reconfirm-info-right {
|
.setting-reconfirm-info-right {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevents icon from large account linking sections, such as the git bridge,
|
||||||
|
// from rendering in the center of the widget, anchoring it to the top
|
||||||
|
.linking-icon-fixed-position {
|
||||||
|
align-self: start;
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// overrides the default `Col` padding, as the inner `affiliations-table-cell` has its own padding, and
|
||||||
|
// the content length of the git-bridge token table is pretty much fixed (tokens and dates)
|
||||||
|
.linking-git-bridge-table-cell {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.linking-git-bridge-revoke-button {
|
||||||
|
padding: 2px 4px;
|
||||||
|
}
|
||||||
|
|
|
@ -90,6 +90,12 @@ h6,
|
||||||
font-size: @font-size-h6;
|
font-size: @font-size-h6;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ui-heading {
|
||||||
|
font-family: @font-family-sans-serif;
|
||||||
|
font-size: @font-size-h4;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
// Body text
|
// Body text
|
||||||
// -------------------------
|
// -------------------------
|
||||||
|
|
||||||
|
@ -191,6 +197,9 @@ cite {
|
||||||
.text-uppercase {
|
.text-uppercase {
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
}
|
}
|
||||||
|
.text-italic {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
// Contextual backgrounds
|
// Contextual backgrounds
|
||||||
// For now we'll leave these alongside the text classes until v4 when we can
|
// For now we'll leave these alongside the text classes until v4 when we can
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
"add_affiliation": "Add Affiliation",
|
"add_affiliation": "Add Affiliation",
|
||||||
"add_another_address_line": "Add another address line",
|
"add_another_address_line": "Add another address line",
|
||||||
"add_another_email": "Add another email",
|
"add_another_email": "Add another email",
|
||||||
|
"add_another_token": "Add another token",
|
||||||
"add_comma_separated_emails_help": "Separate multiple email addresses using the comma (,) character.",
|
"add_comma_separated_emails_help": "Separate multiple email addresses using the comma (,) character.",
|
||||||
"add_comment": "Add comment",
|
"add_comment": "Add comment",
|
||||||
"add_company_details": "Add Company Details",
|
"add_company_details": "Add Company Details",
|
||||||
|
@ -281,6 +282,7 @@
|
||||||
"continue_github_merge": "I have manually merged. Continue",
|
"continue_github_merge": "I have manually merged. Continue",
|
||||||
"continue_to": "Continue to __appName__",
|
"continue_to": "Continue to __appName__",
|
||||||
"continue_with_free_plan": "Continue with free plan",
|
"continue_with_free_plan": "Continue with free plan",
|
||||||
|
"copied": "Copied",
|
||||||
"copy": "Copy",
|
"copy": "Copy",
|
||||||
"copy_project": "Copy Project",
|
"copy_project": "Copy Project",
|
||||||
"copying": "Copying",
|
"copying": "Copying",
|
||||||
|
@ -299,6 +301,7 @@
|
||||||
"create_new_tag": "Create new tag",
|
"create_new_tag": "Create new tag",
|
||||||
"create_project_in_github": "Create a GitHub repository",
|
"create_project_in_github": "Create a GitHub repository",
|
||||||
"create_your_first_project": "Create your first project!",
|
"create_your_first_project": "Create your first project!",
|
||||||
|
"created": "created",
|
||||||
"created_at": "Created at",
|
"created_at": "Created at",
|
||||||
"creating": "Creating",
|
"creating": "Creating",
|
||||||
"credit_card": "Credit Card",
|
"credit_card": "Credit Card",
|
||||||
|
@ -332,10 +335,13 @@
|
||||||
"delete_acct_no_existing_pw": "Please use the password reset form to set a password before deleting your account",
|
"delete_acct_no_existing_pw": "Please use the password reset form to set a password before deleting your account",
|
||||||
"delete_and_leave": "Delete / Leave",
|
"delete_and_leave": "Delete / Leave",
|
||||||
"delete_and_leave_projects": "Delete and Leave Projects",
|
"delete_and_leave_projects": "Delete and Leave Projects",
|
||||||
|
"delete_authentication_token": "Delete Authentication token",
|
||||||
|
"delete_authentication_token_info": "You’re about to delete a Git authentication token. If you do, it can no longer be used to authenticate your identity when performing Git operations.",
|
||||||
"delete_figure": "Delete figure",
|
"delete_figure": "Delete figure",
|
||||||
"delete_folder": "Delete Folder",
|
"delete_folder": "Delete Folder",
|
||||||
"delete_projects": "Delete Projects",
|
"delete_projects": "Delete Projects",
|
||||||
"delete_tag": "Delete Tag",
|
"delete_tag": "Delete Tag",
|
||||||
|
"delete_token": "Delete token",
|
||||||
"delete_your_account": "Delete your account",
|
"delete_your_account": "Delete your account",
|
||||||
"deleted_at": "Deleted At",
|
"deleted_at": "Deleted At",
|
||||||
"deleted_files": "Deleted Files",
|
"deleted_files": "Deleted Files",
|
||||||
|
@ -452,6 +458,7 @@
|
||||||
"example_project": "Example Project",
|
"example_project": "Example Project",
|
||||||
"existing_plan_active_until_term_end": "Your existing plan and its features will remain active until the end of the current billing period.",
|
"existing_plan_active_until_term_end": "Your existing plan and its features will remain active until the end of the current billing period.",
|
||||||
"expand": "Expand",
|
"expand": "Expand",
|
||||||
|
"expires": "Expires",
|
||||||
"expiry": "Expiry Date",
|
"expiry": "Expiry Date",
|
||||||
"export_csv": "Export CSV",
|
"export_csv": "Export CSV",
|
||||||
"export_project_to_github": "Export Project to GitHub",
|
"export_project_to_github": "Export Project to GitHub",
|
||||||
|
@ -581,6 +588,7 @@
|
||||||
"galileo_suggestion_feedback_button": "Was this suggestion useful?",
|
"galileo_suggestion_feedback_button": "Was this suggestion useful?",
|
||||||
"galileo_suggestions_loading_error": "Error loading Galileo suggestions",
|
"galileo_suggestions_loading_error": "Error loading Galileo suggestions",
|
||||||
"galileo_toggle_description": "Toggle Galileo",
|
"galileo_toggle_description": "Toggle Galileo",
|
||||||
|
"generate_token": "Generate token",
|
||||||
"generic_history_error": "Something went wrong trying to fetch your project’s history. If the error persists, please contact us via:",
|
"generic_history_error": "Something went wrong trying to fetch your project’s history. If the error persists, please contact us via:",
|
||||||
"generic_if_problem_continues_contact_us": "If the problem continues please contact us",
|
"generic_if_problem_continues_contact_us": "If the problem continues please contact us",
|
||||||
"generic_linked_file_compile_error": "This project’s output files are not available because it failed to compile. Please open the project to see the compilation error details.",
|
"generic_linked_file_compile_error": "This project’s output files are not available because it failed to compile. Please open the project to see the compilation error details.",
|
||||||
|
@ -595,7 +603,12 @@
|
||||||
"get_started_now": "Get started now",
|
"get_started_now": "Get started now",
|
||||||
"get_the_most_out_headline": "Get the most out of __appName__ with features such as:",
|
"get_the_most_out_headline": "Get the most out of __appName__ with features such as:",
|
||||||
"git": "Git",
|
"git": "Git",
|
||||||
|
"git_authentication_token": "Git authentication token",
|
||||||
|
"git_authentication_token_create_modal_info_1": "This is your Git authentication token. You should enter this when prompted for a password.",
|
||||||
|
"git_authentication_token_create_modal_info_2": "<0>You will only see this authentication token once so please copy it and keep it safe</0>. For full instructions on using authentication tokens, visit our <1>help page</1>.",
|
||||||
"git_bridge_modal_description": "You can <code>git</code> <code>clone</code> your project using the link displayed below.",
|
"git_bridge_modal_description": "You can <code>git</code> <code>clone</code> your project using the link displayed below.",
|
||||||
|
"git_integration": "Git Integration",
|
||||||
|
"git_integration_info": "With Git integration, you can clone your Overleaf projects with Git. For full instructions on how to do this, read <0>our help page</0>.",
|
||||||
"git_integration_lowercase": "Git integration",
|
"git_integration_lowercase": "Git integration",
|
||||||
"git_integration_lowercase_info": "You can clone your Overleaf project to a local repository, treating your Overleaf project as a remote repository that changes can be pushed to and pulled from.",
|
"git_integration_lowercase_info": "You can clone your Overleaf project to a local repository, treating your Overleaf project as a remote repository that changes can be pushed to and pulled from.",
|
||||||
"github_commit_message_placeholder": "Commit message for changes made in __appName__...",
|
"github_commit_message_placeholder": "Commit message for changes made in __appName__...",
|
||||||
|
@ -814,6 +827,7 @@
|
||||||
"last_resort_trouble_shooting_guide": "If that doesn’t help, follow our <0>troubleshooting guide</0>.",
|
"last_resort_trouble_shooting_guide": "If that doesn’t help, follow our <0>troubleshooting guide</0>.",
|
||||||
"last_updated": "Last Updated",
|
"last_updated": "Last Updated",
|
||||||
"last_updated_date_by_x": "__lastUpdatedDate__ by __person__",
|
"last_updated_date_by_x": "__lastUpdatedDate__ by __person__",
|
||||||
|
"last_used": "last used",
|
||||||
"latex_editor_info": "Everything you need in a modern LaTeX editor --- spell check, intelligent autocomplete, syntax highlighting, dozens of color themes, vim and emacs bindings, help with LaTeX warnings and error messages, and much more.",
|
"latex_editor_info": "Everything you need in a modern LaTeX editor --- spell check, intelligent autocomplete, syntax highlighting, dozens of color themes, vim and emacs bindings, help with LaTeX warnings and error messages, and much more.",
|
||||||
"latex_guides": "LaTeX guides",
|
"latex_guides": "LaTeX guides",
|
||||||
"latex_help_guide": "LaTeX help guide",
|
"latex_help_guide": "LaTeX help guide",
|
||||||
|
@ -1571,7 +1585,9 @@
|
||||||
"to_many_login_requests_2_mins": "This account has had too many login requests. Please wait 2 minutes before trying to log in again",
|
"to_many_login_requests_2_mins": "This account has had too many login requests. Please wait 2 minutes before trying to log in again",
|
||||||
"to_modify_your_subscription_go_to": "To modify your subscription go to",
|
"to_modify_your_subscription_go_to": "To modify your subscription go to",
|
||||||
"toggle_compile_options_menu": "Toggle compile options menu",
|
"toggle_compile_options_menu": "Toggle compile options menu",
|
||||||
|
"token": "token",
|
||||||
"token_access_failure": "Cannot grant access; contact the project owner for help",
|
"token_access_failure": "Cannot grant access; contact the project owner for help",
|
||||||
|
"token_limit_reached": "You’ve reached the 10 token limit. To generate a new authentication token, please delete an existing one.",
|
||||||
"token_read_only": "token read-only",
|
"token_read_only": "token read-only",
|
||||||
"token_read_write": "token read-write",
|
"token_read_write": "token read-write",
|
||||||
"too_many_attempts": "Too many attempts. Please wait for a while and try again.",
|
"too_many_attempts": "Too many attempts. Please wait for a while and try again.",
|
||||||
|
@ -1778,6 +1794,13 @@
|
||||||
"you_will_be_able_to_contact_us_any_time_to_share_your_feedback": "<0>You will be able to contact us</0> any time to share your feedback",
|
"you_will_be_able_to_contact_us_any_time_to_share_your_feedback": "<0>You will be able to contact us</0> any time to share your feedback",
|
||||||
"your_affiliation_is_confirmed": "Your <0>__institutionName__</0> affiliation is confirmed.",
|
"your_affiliation_is_confirmed": "Your <0>__institutionName__</0> affiliation is confirmed.",
|
||||||
"your_browser_does_not_support_this_feature": "Sorry, your browser doesn’t support this feature. Please update your browser to its latest version.",
|
"your_browser_does_not_support_this_feature": "Sorry, your browser doesn’t support this feature. Please update your browser to its latest version.",
|
||||||
|
"your_git_access_info": "Your Git authentication tokens should be entered whenever you’re prompted for a password.",
|
||||||
|
"your_git_access_info_bullet_1": "You can have up to 10 tokens.",
|
||||||
|
"your_git_access_info_bullet_2": "If you reach the maximum limit, you’ll need to delete a token before you can generate a new one.",
|
||||||
|
"your_git_access_info_bullet_3": "You can generate a token using the <0>Generate token</0> button.",
|
||||||
|
"your_git_access_info_bullet_4": "You won’t be able to view the full token after the first time you generate it. Please copy it and keep it safe",
|
||||||
|
"your_git_access_info_bullet_5": "Previously generated tokens will be shown here.",
|
||||||
|
"your_git_access_tokens": "Your Git authentication tokens",
|
||||||
"your_message_to_collaborators": "Send a message to your collaborators",
|
"your_message_to_collaborators": "Send a message to your collaborators",
|
||||||
"your_new_plan": "Your new plan",
|
"your_new_plan": "Your new plan",
|
||||||
"your_password_has_been_successfully_changed": "Your password has been successfully changed",
|
"your_password_has_been_successfully_changed": "Your password has been successfully changed",
|
||||||
|
|
|
@ -70,6 +70,9 @@ describe('UserPagesController', function () {
|
||||||
this.Features = {
|
this.Features = {
|
||||||
hasFeature: sinon.stub().returns(false),
|
hasFeature: sinon.stub().returns(false),
|
||||||
}
|
}
|
||||||
|
this.PersonalAccessTokenManager = {
|
||||||
|
listTokens: sinon.stub().returns([]),
|
||||||
|
}
|
||||||
this.UserPagesController = SandboxedModule.require(modulePath, {
|
this.UserPagesController = SandboxedModule.require(modulePath, {
|
||||||
requires: {
|
requires: {
|
||||||
'@overleaf/settings': this.settings,
|
'@overleaf/settings': this.settings,
|
||||||
|
@ -80,6 +83,8 @@ describe('UserPagesController', function () {
|
||||||
'../Authentication/AuthenticationController':
|
'../Authentication/AuthenticationController':
|
||||||
this.AuthenticationController,
|
this.AuthenticationController,
|
||||||
'../../infrastructure/Features': this.Features,
|
'../../infrastructure/Features': this.Features,
|
||||||
|
'../../../../modules/oauth2-server/app/src/OAuthPersonalAccessTokenManager':
|
||||||
|
this.PersonalAccessTokenManager,
|
||||||
'../Authentication/SessionManager': this.SessionManager,
|
'../Authentication/SessionManager': this.SessionManager,
|
||||||
request: (this.request = sinon.stub()),
|
request: (this.request = sinon.stub()),
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,5 +32,8 @@ declare global {
|
||||||
_reportAcePerf: () => void
|
_reportAcePerf: () => void
|
||||||
MathJax: Record<string, any>
|
MathJax: Record<string, any>
|
||||||
overallThemes: OverallThemeMeta[]
|
overallThemes: OverallThemeMeta[]
|
||||||
|
crypto: {
|
||||||
|
randomUUID: () => string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue