overleaf/services/web/frontend/js/utils/meta.ts
Antoine Clausse 2c7530a6cf [web] Set Subscription pages to have layout-react (#20969)
* [web] Set Subscription pages to have `layout-react`

* [web] import `header-footer-react` in Subscription pages (!!)

* [web] Add `ol-user` meta tag to the subscription pages (!!)

⚠️ invite_logged_out.pug should be updated instead of setting the user as `{}`

* [web] Fix unit test

* [web] Update User types to handle a logged out user, add `LOGGED_OUT_USER` const

* [web] Add type `User` to `getSessionUser`

* [web] Remove `LOGGED_OUT_USER` const

* [web] Just pass `{ id: null }` as the user

* [web] Remove comment in pugs, it breaks things

* [web] Don't pass the full user to the frontend!!!

Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>

---------

Co-authored-by: Jakob Ackermann <jakob.ackermann@overleaf.com>
GitOrigin-RevId: 1768f1f13de924a18be43c1a08614000500dcbec
2024-10-18 08:05:53 +00:00

260 lines
10 KiB
TypeScript

import { User, Features, LoggedOutUser } from '../../../types/user'
import { User as MinimalUser } from '../../../types/admin/user'
import { User as ManagedUser } from '../../../types/group-management/user'
import { UserSettings } from '../../../types/user-settings'
import { OAuthProviders } from '../../../types/oauth-providers'
import { ExposedSettings } from '../../../types/exposed-settings'
import {
type AllowedImageName,
OverallThemeMeta,
type SpellCheckLanguage,
} from '../../../types/project-settings'
import { CurrencyCode } from '../../../types/subscription/currency'
import { PricingFormState } from '../../../types/subscription/payment-context-value'
import { Plan } from '../../../types/subscription/plan'
import { Affiliation } from '../../../types/affiliation'
import type { PortalTemplate } from '../../../types/portal-template'
import { UserEmailData } from '../../../types/user-email'
import {
GroupsAndEnterpriseBannerVariant,
Institution as InstitutionType,
Notification as NotificationType,
PendingGroupSubscriptionEnrollment,
USGovBannerVariant,
} from '../../../types/project/dashboard/notification'
import { Survey } from '../../../types/project/dashboard/survey'
import { GetProjectsResponseBody } from '../../../types/project/dashboard/api'
import { Tag } from '../../../app/src/Features/Tags/types'
import { Institution } from '../../../types/institution'
import {
ManagedGroupSubscription,
MemberGroupSubscription,
} from '../../../types/subscription/dashboard/subscription'
import { SplitTestInfo } from '../../../types/split-test'
import { ValidationStatus } from '../../../types/group-management/validation'
import { ManagedInstitution } from '../../../types/subscription/dashboard/managed-institution'
import { GroupSSOTestResult } from '../../../modules/group-settings/frontend/js/utils/types'
import {
AccessToken,
InstitutionLink,
SAMLError,
} from '../../../types/settings-page'
import { SuggestedLanguage } from '../../../types/system-message'
import type { TeamInvite } from '../../../types/team-invite'
import { GroupPlans } from '../../../types/subscription/dashboard/group-plans'
import { GroupSSOLinkingStatus } from '../../../types/subscription/sso'
import { PasswordStrengthOptions } from '../../../types/password-strength-options'
import { Subscription as ProjectDashboardSubscription } from '../../../types/project/dashboard/subscription'
import { ThirdPartyIds } from '../../../types/third-party-ids'
import { Publisher } from '../../../types/subscription/dashboard/publisher'
import { DefaultNavbarMetadata } from '@/features/ui/components/types/default-navbar-metadata'
import { FatFooterMetadata } from '@/features/ui/components/types/fat-footer-metadata'
export interface Meta {
'ol-ExposedSettings': ExposedSettings
'ol-allInReconfirmNotificationPeriods': UserEmailData[]
'ol-allowedExperiments': string[]
'ol-allowedImageNames': AllowedImageName[]
'ol-anonymous': boolean
'ol-baseAssetPath': string
'ol-bootstrapVersion': 3 | 5
'ol-brandVariation': Record<string, any>
// dynamic keys based on permissions
'ol-cannot-add-secondary-email': boolean
'ol-cannot-change-password': boolean
'ol-cannot-delete-own-account': boolean
'ol-cannot-join-subscription': boolean
'ol-cannot-leave-group-subscription': boolean
'ol-cannot-link-google-sso': boolean
'ol-cannot-link-other-third-party-sso': boolean
'ol-cannot-reactivate-subscription': boolean
'ol-cannot-use-ai': boolean
'ol-chatEnabled': boolean
'ol-countryCode': PricingFormState['country']
'ol-couponCode': PricingFormState['coupon']
'ol-createdAt': Date
'ol-csrfToken': string
'ol-currentInstitutionsWithLicence': Institution[]
'ol-currentManagedUserAdminEmail': string
'ol-currentUrl': string
'ol-debugPdfDetach': boolean
'ol-detachRole': 'detached' | 'detacher' | ''
'ol-dictionariesRoot': 'string'
'ol-dropbox': { error: boolean; registered: boolean }
'ol-editorThemes': string[]
'ol-email': string
'ol-emailAddressLimit': number
'ol-error': { name: string } | undefined
'ol-expired': boolean
'ol-features': Features
'ol-footer': FatFooterMetadata
'ol-fromPlansPage': boolean
'ol-gitBridgeEnabled': boolean
'ol-gitBridgePublicBaseUrl': string
'ol-github': { enabled: boolean; error: boolean }
'ol-groupId': string
'ol-groupName': string
'ol-groupPlans': GroupPlans
'ol-groupSSOActive': boolean
'ol-groupSSOTestResult': GroupSSOTestResult
'ol-groupSettingsEnabledFor': string[]
'ol-groupSize': number
'ol-groupSsoSetupSuccess': boolean
'ol-groupSubscriptionsPendingEnrollment': PendingGroupSubscriptionEnrollment[]
'ol-groupsAndEnterpriseBannerVariant': GroupsAndEnterpriseBannerVariant
'ol-hasGroupSSOFeature': boolean
'ol-hasIndividualRecurlySubscription': boolean
'ol-hasManagedUsersFeature': boolean
'ol-hasPassword': boolean
'ol-hasSubscription': boolean
'ol-hasTrackChangesFeature': boolean
'ol-hideLinkingWidgets': boolean // CI only
'ol-i18n': { currentLangCode: string }
'ol-inactiveTutorials': string[]
'ol-institutionEmailNonCanonical': string | undefined
'ol-institutionLinked': InstitutionLink | undefined
'ol-inviteToken': string
'ol-inviterName': string
'ol-isExternalAuthenticationSystemUsed': boolean
'ol-isManagedAccount': boolean
'ol-isProfessional': boolean
'ol-isRegisteredViaGoogle': boolean
'ol-isRestrictedTokenMember': boolean
'ol-isSaas': boolean
'ol-itm_campaign': string
'ol-itm_content': string
'ol-itm_referrer': string
'ol-labs': boolean
'ol-languages': SpellCheckLanguage[]
'ol-learnedWords': string[]
'ol-legacyEditorThemes': string[]
'ol-linkSharingEnforcement': boolean
'ol-linkSharingWarning': boolean
'ol-loadingText': string
'ol-managedGroupSubscriptions': ManagedGroupSubscription[]
'ol-managedInstitutions': ManagedInstitution[]
'ol-managedPublishers': Publisher[]
'ol-managedUsersActive': boolean
'ol-managedUsersEnabled': boolean
'ol-managers': MinimalUser[]
'ol-mathJaxPath': string
'ol-maxDocLength': number
'ol-memberGroupSubscriptions': MemberGroupSubscription[]
'ol-memberOfSSOEnabledGroups': GroupSSOLinkingStatus[]
'ol-members': MinimalUser[]
'ol-navbar': DefaultNavbarMetadata
'ol-no-single-dollar': boolean
'ol-notifications': NotificationType[]
'ol-notificationsInstitution': InstitutionType[]
'ol-oauthProviders': OAuthProviders
'ol-overallThemes': OverallThemeMeta[]
'ol-passwordStrengthOptions': PasswordStrengthOptions
'ol-personalAccessTokens': AccessToken[] | undefined
'ol-plan': Plan
'ol-planCode': string
'ol-planCodesChangingAtTermEnd': string[] | undefined
'ol-plans': Plan[]
'ol-portalTemplates': PortalTemplate[]
'ol-postCheckoutRedirect': string
'ol-postUrl': string
'ol-prefetchedProjectsBlob': GetProjectsResponseBody | undefined
'ol-primaryEmail': { email: string; confirmed: boolean }
'ol-project': any // TODO
'ol-projectSyncSuccessMessage': string
'ol-projectTags': Tag[]
'ol-project_id': string
'ol-recommendedCurrency': CurrencyCode
'ol-reconfirmationRemoveEmail': string
'ol-reconfirmedViaSAML': string
'ol-recurlyApiKey': string
'ol-recurlySubdomain': string
'ol-ro-mirror-on-client-no-local-storage': boolean
'ol-samlError': SAMLError | undefined
'ol-settingsGroupSSO': { enabled: boolean } | undefined
'ol-settingsPlans': Plan[]
'ol-shouldAllowEditingDetails': boolean
'ol-showAiErrorAssistant': boolean
'ol-showBrlGeoBanner': boolean
'ol-showCouponField': boolean
'ol-showGroupsAndEnterpriseBanner': boolean
'ol-showInrGeoBanner': boolean
'ol-showLATAMBanner': boolean
'ol-showSupport': boolean
'ol-showSymbolPalette': boolean
'ol-showTemplatesServerPro': boolean
'ol-showUSGovBanner': boolean
'ol-showUpgradePrompt': boolean
'ol-skipUrl': string
'ol-splitTestInfo': { [name: string]: SplitTestInfo }
'ol-splitTestVariants': { [name: string]: string }
'ol-ssoDisabled': boolean
'ol-ssoErrorMessage': string
'ol-subscription': any // TODO: mixed types, split into two fields
'ol-subscriptionId': string
'ol-suggestedLanguage': SuggestedLanguage | undefined
'ol-survey': Survey | undefined
'ol-symbolPaletteAvailable': boolean
'ol-tags': Tag[]
'ol-teamInvites': TeamInvite[]
'ol-thirdPartyIds': ThirdPartyIds
'ol-translationIoNotLoaded': string
'ol-translationLoadErrorMessage': string
'ol-translationMaintenance': string
'ol-translationUnableToJoin': string
'ol-usGovBannerVariant': USGovBannerVariant
'ol-useShareJsHash': boolean
'ol-usedLatex': 'never' | 'occasionally' | 'often' | undefined
'ol-user': User | LoggedOutUser
'ol-userAffiliations': Affiliation[]
'ol-userCanExtendTrial': boolean
'ol-userCanNotStartRequestedTrial': boolean
'ol-userEmails': UserEmailData[]
'ol-userSettings': UserSettings
'ol-user_id': string | undefined
'ol-users': ManagedUser[]
'ol-usersBestSubscription': ProjectDashboardSubscription | undefined
'ol-usersEmail': string | undefined
'ol-validationStatus': ValidationStatus
'ol-websiteRedesignPlansVariant': 'default' | 'light-design' | 'new-design'
'ol-wikiEnabled': boolean
'ol-writefullCssUrl': string
'ol-writefullEnabled': boolean
'ol-writefullJsUrl': string
'ol-wsUrl': string
}
// cache for parsed values
window.metaAttributesCache = window.metaAttributesCache || new Map()
export default function getMeta<T extends keyof Meta>(name: T): Meta[T] {
if (window.metaAttributesCache.has(name)) {
return window.metaAttributesCache.get(name)
}
const element = document.head.querySelector(
`meta[name="${name}"]`
) as HTMLMetaElement
if (!element) {
return undefined!
}
const plainTextValue = element.content
let value
switch (element.dataset.type) {
case 'boolean':
// in pug: content=false -> no content field
// in pug: content=true -> empty content field
value = element.hasAttribute('content')
break
case 'json':
if (!plainTextValue) {
// JSON.parse('') throws
value = undefined
} else {
value = JSON.parse(plainTextValue)
}
break
default:
value = plainTextValue
}
window.metaAttributesCache.set(name, value)
return value
}