| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- // End of third-party imports
- import {
- DocsSearchResultType as PageType,
- type DocsSearchResult as Page,
- type DocsSearchResultSection as PageSection,
- } from 'common'
- import dayjs from 'dayjs'
- import { partition } from 'lodash'
- import { Book, Github, Hash, MessageSquare } from 'lucide-react'
- import {
- createLoader,
- createParser,
- createSerializer,
- parseAsString,
- type inferParserType,
- type UseQueryStatesKeysMap,
- } from 'nuqs'
- import { CATEGORY_OPTIONS } from './Support.constants'
- import { getProjectDetail } from '@/data/projects/project-detail-query'
- import { DOCS_URL } from '@/lib/constants'
- import type { Organization } from '@/types'
- export const NO_PROJECT_MARKER = 'no-project'
- export const NO_ORG_MARKER = 'no-org'
- export const formatMessage = ({
- message,
- attachments = [],
- error,
- }: {
- message: string
- attachments?: Array<string>
- error: string | null | undefined
- }) => {
- const [harFiles, images] = partition(attachments, (x) => x.split('?token')[0].endsWith('.har'))
- const errorString = error != null ? `\n\nError: ${error}` : ''
- const imagesString = images.length > 0 ? `\n\nImage Attachments:\n${images.join('\n\n')}` : ''
- const harFilesString = harFiles.length > 0 ? `\n\nHAR Files:\n${harFiles.join('\n\n')}` : ''
- return `${message}${errorString}${imagesString}${harFilesString}`
- }
- export const formatStudioVersion = (commit: { commitSha: string; commitTime: string }): string => {
- const formattedTime =
- commit.commitTime === 'unknown'
- ? 'unknown time'
- : dayjs(commit.commitTime).format('YYYY-MM-DD HH:mm:ss Z')
- return `SHA ${commit.commitSha} deployed at ${formattedTime}`
- }
- export function getPageIcon(page: Page) {
- switch (page.type) {
- case PageType.Markdown:
- case PageType.Reference:
- case PageType.Integration:
- return <Book strokeWidth={1.5} className="mr-0! w-4! h-4!" />
- case PageType.GithubDiscussion:
- return <Github strokeWidth={1.5} className="mr-0! w-4! h-4!" />
- default:
- throw new Error(`Unknown page type '${page.type}'`)
- }
- }
- export function getPageSectionIcon(page: Page) {
- switch (page.type) {
- case PageType.Markdown:
- case PageType.Reference:
- case PageType.Integration:
- return <Hash strokeWidth={1.5} className="mr-0! w-4! h-4!" />
- case PageType.GithubDiscussion:
- return <MessageSquare strokeWidth={1.5} className="mr-0! w-4! h-4!" />
- default:
- throw new Error(`Unknown page type '${page.type}'`)
- }
- }
- export function generateLink(pageType: PageType, link: string): string {
- switch (pageType) {
- case PageType.Markdown:
- case PageType.Reference:
- return `${DOCS_URL}${link}`
- case PageType.Integration:
- return `https://supabase.com${link}`
- case PageType.GithubDiscussion:
- return link
- default:
- throw new Error(`Unknown page type '${pageType}'`)
- }
- }
- export function formatSectionUrl(page: Page, section: PageSection): string {
- switch (page.type) {
- case PageType.Markdown:
- case PageType.GithubDiscussion:
- return `${generateLink(page.type, page.path)}#${section.slug ?? ''}`
- case PageType.Reference:
- return `${generateLink(page.type, page.path)}/${section.slug ?? ''}`
- case PageType.Integration:
- return generateLink(page.type, page.path) // Assuming no section slug for Integration pages
- default:
- throw new Error(`Unknown page type '${page.type}'`)
- }
- }
- export function getOrgSubscriptionPlan(orgs: Organization[] | undefined, orgSlug: string | null) {
- if (!orgs || !orgSlug) return undefined
- const selectedOrg = orgs?.find((org) => org.slug === orgSlug)
- const subscriptionPlanId = selectedOrg?.plan.id
- return subscriptionPlanId
- }
- const categoryOptionsLower = CATEGORY_OPTIONS.map((option) => option.value.toLowerCase())
- const parseAsCategoryOption = createParser({
- parse(queryValue) {
- const lowerValue = queryValue.toLowerCase()
- const matchingIndex = categoryOptionsLower.indexOf(lowerValue)
- return matchingIndex !== -1 ? CATEGORY_OPTIONS[matchingIndex].value : null
- },
- serialize(value) {
- return value ?? null
- },
- })
- const supportFormUrlState = {
- projectRef: parseAsString.withDefault(''),
- orgSlug: parseAsString.withDefault(''),
- category: parseAsCategoryOption,
- subject: parseAsString.withDefault(''),
- message: parseAsString.withDefault(''),
- error: parseAsString,
- /** Sentry event ID */
- sid: parseAsString,
- } satisfies UseQueryStatesKeysMap
- export type SupportFormUrlKeys = inferParserType<typeof supportFormUrlState>
- export const loadSupportFormInitialParams = createLoader(supportFormUrlState)
- export function loadSupportFormInitialParamsFromObject(
- initialParams: Partial<SupportFormUrlKeys>
- ): SupportFormUrlKeys {
- const normalizedParams = Object.fromEntries(
- Object.entries(initialParams).flatMap(([key, value]) =>
- value == null ? [] : [[key, String(value)]]
- )
- )
- return loadSupportFormInitialParams(normalizedParams)
- }
- const serializeSupportFormInitialParams = createSerializer(supportFormUrlState)
- export function createSupportFormUrl(initialParams: Partial<SupportFormUrlKeys>) {
- const serializedParams = serializeSupportFormInitialParams(initialParams)
- const query = serializedParams && serializedParams !== '?' ? serializedParams : ''
- return `/support/new${query}`
- }
- /**
- * Determines which organization to select based on combination of:
- * - Selected project (if any)
- * - URL param (if any)
- * - Fallback
- */
- export async function selectInitialOrgAndProject({
- projectRef,
- orgSlug,
- orgs,
- }: {
- projectRef: string | null
- orgSlug: string | null
- orgs: Organization[]
- }): Promise<{ projectRef: string | null; orgSlug: string | null }> {
- if (projectRef) {
- try {
- const projectDetails = await getProjectDetail({ ref: projectRef })
- if (projectDetails?.organization_id) {
- const org = orgs.find((o) => o.id === projectDetails.organization_id)
- if (org?.slug) {
- return {
- projectRef,
- orgSlug: org.slug,
- }
- }
- }
- } catch {
- // Can safely ignore, consider provided project ref invalid
- }
- }
- if (orgSlug) {
- const org = orgs.find((o) => o.slug === orgSlug)
- if (org?.slug) {
- return {
- projectRef: null,
- orgSlug: org.slug,
- }
- }
- }
- return {
- projectRef: null,
- orgSlug: orgs[0]?.slug ?? null,
- }
- }
|