mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-12 05:48:57 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7375d3c597 | |||
| 3548fa6dff | |||
| cb73040e0f | |||
| 872d36b64f | |||
| e1ff17e655 | |||
| f3010bd28a | |||
| 8ff1e3b619 | |||
| d7596bf454 | |||
| aea5eb10ae | |||
| 1165a81cf5 | |||
| 61d1a0192e | |||
| f9a2977621 | |||
| 24f601d594 |
+1
-1
@@ -34,7 +34,7 @@
|
|||||||
"workspaces": {
|
"workspaces": {
|
||||||
"packages": ["packages/*"],
|
"packages": ["packages/*"],
|
||||||
"catalog": {
|
"catalog": {
|
||||||
"@gitbook/api": "^0.139.0",
|
"@gitbook/api": "^0.140.0",
|
||||||
"bidc": "^0.0.2"
|
"bidc": "^0.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
# @gitbook/expr
|
# @gitbook/expr
|
||||||
|
|
||||||
|
## 1.1.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 3548fa6: Fix eval-estree-expr named import
|
||||||
|
|
||||||
|
## 1.1.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- e1ff17e: Fix bundling of gitbook/expr package
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 8ff1e3b: Add support for every/some array methods
|
||||||
|
|
||||||
## 1.0.0
|
## 1.0.0
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@gitbook/expr",
|
"name": "@gitbook/expr",
|
||||||
"description": "Safely evaluate & parse user-defined GitBook expressions.",
|
"description": "Safely evaluate & parse user-defined GitBook expressions.",
|
||||||
"version": "1.0.0",
|
"version": "1.1.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
@@ -12,23 +12,26 @@
|
|||||||
},
|
},
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"eval-estree-expression": "^2.0.3",
|
"eval-estree-expression": "github:jonschlinkert/eval-estree-expression#9cf28d2",
|
||||||
"acorn": "^8.14.0",
|
"acorn": "^8.14.0",
|
||||||
"acorn-loose": "8.4.0",
|
"acorn-loose": "8.4.0",
|
||||||
"acorn-walk": "^8.3.4",
|
"acorn-walk": "^8.3.4",
|
||||||
|
"escodegen": "^2.1.0",
|
||||||
"assert-never": "^1.2.1"
|
"assert-never": "^1.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bun-types": "^1.1.20",
|
"bun-types": "^1.1.20",
|
||||||
|
"tsdown": "^0.15.0",
|
||||||
"@types/estree": "^1.0.6",
|
"@types/estree": "^1.0.6",
|
||||||
"@babel/types": "^7.26.0",
|
"@babel/types": "^7.26.0",
|
||||||
"@types/json-schema": "^7.0.15"
|
"@types/json-schema": "^7.0.15",
|
||||||
|
"@types/escodegen": "^0.0.10"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc --project tsconfig.build.json",
|
"build": "tsdown --project tsconfig.build.json",
|
||||||
"typecheck": "tsc --noEmit",
|
"typecheck": "tsc --noEmit",
|
||||||
"unit": "bun test",
|
"unit": "bun test",
|
||||||
"clean": "rm -rf ./dist"
|
"clean": "rm -rf ./dist"
|
||||||
},
|
},
|
||||||
"files": ["dist", "src", "README.md", "CHANGELOG.md"]
|
"files": ["dist", "README.md", "CHANGELOG.md"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,6 +210,8 @@ describe('autocomplete', () => {
|
|||||||
'visitor.claims.hello.length',
|
'visitor.claims.hello.length',
|
||||||
'visitor.claims.hello.at',
|
'visitor.claims.hello.at',
|
||||||
'visitor.claims.hello.includes',
|
'visitor.claims.hello.includes',
|
||||||
|
'visitor.claims.hello.some',
|
||||||
|
'visitor.claims.hello.every',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -268,6 +270,8 @@ describe('autocomplete', () => {
|
|||||||
'visitor.claims.hello.length',
|
'visitor.claims.hello.length',
|
||||||
'visitor.claims.hello.at',
|
'visitor.claims.hello.at',
|
||||||
'visitor.claims.hello.includes',
|
'visitor.claims.hello.includes',
|
||||||
|
'visitor.claims.hello.some',
|
||||||
|
'visitor.claims.hello.every',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,11 +42,29 @@ describe('ExpressionRuntime', () => {
|
|||||||
},
|
},
|
||||||
expectedResult: true,
|
expectedResult: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
scenario: 'array method',
|
||||||
|
condition: 'reviews.every(review => !!review.status)',
|
||||||
|
inputs: { reviews: [{ status: 'approved' }, { status: 'approved' }] },
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: 'array every',
|
||||||
|
condition: 'reviews.every(review => review.status === "approved")',
|
||||||
|
inputs: { reviews: [{ status: 'approved' }, { status: 'approved' }] },
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scenario: 'array map',
|
||||||
|
condition: '[1, 2, 3].map(n => n * x)',
|
||||||
|
inputs: { x: 2 },
|
||||||
|
expectedResult: [2, 4, 6],
|
||||||
|
},
|
||||||
])(
|
])(
|
||||||
'should properly evaluate/safeEvaluate a valid conditional expression: $scenario',
|
'should properly evaluate/safeEvaluate a valid conditional expression: $scenario',
|
||||||
({ condition, inputs, expectedResult }) => {
|
({ condition, inputs, expectedResult }) => {
|
||||||
expect(runtime.evaluate(condition, inputs)).toBe(expectedResult);
|
expect(runtime.evaluate(condition, inputs)).toEqual(expectedResult);
|
||||||
expect(runtime.safeEvaluate(condition, inputs).value).toBe(expectedResult);
|
expect(runtime.safeEvaluate(condition, inputs).value).toEqual(expectedResult);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
export * from './errors';
|
export * from './errors';
|
||||||
export * from './input-values';
|
export * from './input-values';
|
||||||
export * from './input-values';
|
|
||||||
export * from './runtime';
|
export * from './runtime';
|
||||||
export * from './symbols';
|
export * from './symbols';
|
||||||
export * from './template';
|
export * from './template';
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import {
|
|||||||
tokenizer,
|
tokenizer,
|
||||||
} from 'acorn';
|
} from 'acorn';
|
||||||
import { parse as parseLoose } from 'acorn-loose';
|
import { parse as parseLoose } from 'acorn-loose';
|
||||||
import { evaluate } from 'eval-estree-expression';
|
import escodegen from 'escodegen';
|
||||||
|
import evalESTreeExpr from 'eval-estree-expression';
|
||||||
|
const { evaluate } = evalESTreeExpr;
|
||||||
|
|
||||||
import { AutoComplete } from './autocomplete';
|
import { AutoComplete } from './autocomplete';
|
||||||
import { ExpressionError } from './errors';
|
import { ExpressionError } from './errors';
|
||||||
@@ -49,6 +51,7 @@ export class ExpressionRuntime {
|
|||||||
return evaluate.sync<Expression>(parsed.result, inputs, {
|
return evaluate.sync<Expression>(parsed.result, inputs, {
|
||||||
functions: true,
|
functions: true,
|
||||||
withMembers: true,
|
withMembers: true,
|
||||||
|
generate: escodegen.generate,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error instanceof Error
|
throw error instanceof Error
|
||||||
|
|||||||
@@ -338,6 +338,8 @@ describe('ExpressionRuntime', () => {
|
|||||||
'visitor.claims.hello.length',
|
'visitor.claims.hello.length',
|
||||||
'visitor.claims.hello.at',
|
'visitor.claims.hello.at',
|
||||||
'visitor.claims.hello.includes',
|
'visitor.claims.hello.includes',
|
||||||
|
'visitor.claims.hello.some',
|
||||||
|
'visitor.claims.hello.every',
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -259,6 +259,60 @@ const StandardLibrary: Partial<
|
|||||||
'true if the value searchElement is found within the array (or the part of the array indicated by the index fromIndex, if specified).',
|
'true if the value searchElement is found within the array (or the part of the array indicated by the index fromIndex, if specified).',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
SymbolFunction({
|
||||||
|
name: 'some',
|
||||||
|
description:
|
||||||
|
'Tests whether at least one element in the array passes the test implemented by the provided function.',
|
||||||
|
link: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some',
|
||||||
|
args: [
|
||||||
|
SymbolFunction({
|
||||||
|
name: 'callback',
|
||||||
|
description: 'A function that tests each element of the array.',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
...arraySymbolDef.items,
|
||||||
|
name: 'element',
|
||||||
|
description: 'The current element being processed in the array.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
returns: SymbolBoolean({
|
||||||
|
description:
|
||||||
|
'true if the callback function returns a truthy value for at least one element in the array.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
returns: SymbolBoolean({
|
||||||
|
description:
|
||||||
|
'true if the callback function returns a truthy value for at least one element in the array.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
SymbolFunction({
|
||||||
|
name: 'every',
|
||||||
|
description:
|
||||||
|
'Tests whether all elements in the array pass the test implemented by the provided function.',
|
||||||
|
link: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every',
|
||||||
|
args: [
|
||||||
|
SymbolFunction({
|
||||||
|
name: 'callback',
|
||||||
|
description: 'A function that tests each element of the array.',
|
||||||
|
args: [
|
||||||
|
{
|
||||||
|
...arraySymbolDef.items,
|
||||||
|
name: 'element',
|
||||||
|
description: 'The current element being processed in the array.',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
returns: SymbolBoolean({
|
||||||
|
description:
|
||||||
|
'true if the callback function returns a truthy value for all elements in the array.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
returns: SymbolBoolean({
|
||||||
|
description:
|
||||||
|
'true if the callback function returns a truthy value for all elements in the array.',
|
||||||
|
}),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'tsdown';
|
||||||
|
|
||||||
|
export default defineConfig([
|
||||||
|
{
|
||||||
|
entry: ['src/index.ts'],
|
||||||
|
dts: true,
|
||||||
|
format: ['esm'],
|
||||||
|
},
|
||||||
|
]);
|
||||||
+1
-1
@@ -14,7 +14,7 @@ declare module 'eval-estree-expression' {
|
|||||||
/**
|
/**
|
||||||
* Enable support for function statements and expressions by enabling the functions option AND by passing the .generate() function from the escodegen library. Default: undefined
|
* Enable support for function statements and expressions by enabling the functions option AND by passing the .generate() function from the escodegen library. Default: undefined
|
||||||
*/
|
*/
|
||||||
generate?: boolean;
|
generate?: boolean | ((node: any) => string);
|
||||||
/**
|
/**
|
||||||
* Enable the =~ regex operator to support testing values without using functions (example name =~ /^a.*c$/). Default: true
|
* Enable the =~ regex operator to support testing values without using functions (example name =~ /^a.*c$/). Default: true
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
# gitbook
|
# gitbook
|
||||||
|
|
||||||
|
## 0.17.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- @gitbook/react-openapi@1.4.2
|
||||||
|
|
||||||
|
## 0.17.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 24f601d: Small optim in resolveTryItPrefillForOperation
|
||||||
|
- aea5eb1: Persist language choice across sections if possible
|
||||||
|
- 1165a81: Language selector edge cases
|
||||||
|
- f9a2977: Better handling for external link "mailto:" in Hovered Card in GBO
|
||||||
|
- Updated dependencies [24f601d]
|
||||||
|
- @gitbook/react-openapi@1.4.1
|
||||||
|
|
||||||
## 0.17.0
|
## 0.17.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
"dev": {
|
"dev": {
|
||||||
"vars": {
|
"vars": {
|
||||||
"STAGE": "dev",
|
"STAGE": "dev",
|
||||||
"OPEN_NEXT_REQUEST_ID_HEADER": "true"
|
"OPEN_NEXT_REQUEST_ID_HEADER": "true",
|
||||||
|
"GITBOOK_URL": "http://localhost:8771"
|
||||||
},
|
},
|
||||||
"r2_buckets": [
|
"r2_buckets": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "gitbook",
|
"name": "gitbook",
|
||||||
"version": "0.17.0",
|
"version": "0.17.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/api": "catalog:",
|
"@gitbook/api": "catalog:",
|
||||||
"@gitbook/browser-types": "workspace:*",
|
"@gitbook/browser-types": "workspace:*",
|
||||||
"@gitbook/cache-tags": "workspace:*",
|
"@gitbook/cache-tags": "workspace:*",
|
||||||
"@gitbook/colors": "workspace:*",
|
"@gitbook/colors": "workspace:*",
|
||||||
"@gitbook/expr": "workspace:*",
|
|
||||||
"@gitbook/emoji-codepoints": "workspace:*",
|
"@gitbook/emoji-codepoints": "workspace:*",
|
||||||
"@gitbook/fonts": "workspace:*",
|
"@gitbook/fonts": "workspace:*",
|
||||||
"@gitbook/icons": "workspace:*",
|
"@gitbook/icons": "workspace:*",
|
||||||
@@ -47,7 +46,7 @@
|
|||||||
"memoizee": "^0.4.17",
|
"memoizee": "^0.4.17",
|
||||||
"micromark-extension-frontmatter": "^2.0.0",
|
"micromark-extension-frontmatter": "^2.0.0",
|
||||||
"micromark-extension-gfm": "^3.0.0",
|
"micromark-extension-gfm": "^3.0.0",
|
||||||
"next": "15.3.5",
|
"next": "15.4.0",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"nuqs": "^2.2.3",
|
"nuqs": "^2.2.3",
|
||||||
"object-hash": "^3.0.0",
|
"object-hash": "^3.0.0",
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import type { GitBookSiteContext } from '@/lib/context';
|
import type { GitBookSiteContext } from '@/lib/context';
|
||||||
import { Icon } from '@gitbook/icons';
|
import { Icon } from '@gitbook/icons';
|
||||||
import { headers } from 'next/headers';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { tcls } from '@/lib/tailwind';
|
import { tcls } from '@/lib/tailwind';
|
||||||
|
|
||||||
import { DateRelative } from '../primitives';
|
import { DateRelative } from '../primitives';
|
||||||
|
import { IframeWrapper } from './IframeWrapper';
|
||||||
import { RefreshChangeRequestButton } from './RefreshChangeRequestButton';
|
import { RefreshChangeRequestButton } from './RefreshChangeRequestButton';
|
||||||
import { Toolbar, ToolbarBody, ToolbarButton, ToolbarButtonGroups } from './Toolbar';
|
import { Toolbar, ToolbarBody, ToolbarButton, ToolbarButtonGroups } from './Toolbar';
|
||||||
|
|
||||||
@@ -47,19 +46,21 @@ function ToolbarLayout(props: { children: React.ReactNode }) {
|
|||||||
*/
|
*/
|
||||||
export async function AdminToolbar(props: AdminToolbarProps) {
|
export async function AdminToolbar(props: AdminToolbarProps) {
|
||||||
const { context } = props;
|
const { context } = props;
|
||||||
const mode = (await headers()).get('x-gitbook-mode');
|
|
||||||
|
|
||||||
if (mode === 'multi-id') {
|
|
||||||
// We don't show the admin toolbar in multi-id mode, as it's used for previewing in the dashboard.
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.changeRequest) {
|
if (context.changeRequest) {
|
||||||
return <ChangeRequestToolbar context={context} />;
|
return (
|
||||||
|
<IframeWrapper>
|
||||||
|
<ChangeRequestToolbar context={context} />
|
||||||
|
</IframeWrapper>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.revisionId !== context.space.revision) {
|
if (context.revisionId !== context.space.revision) {
|
||||||
return <RevisionToolbar context={context} />;
|
return (
|
||||||
|
<IframeWrapper>
|
||||||
|
<RevisionToolbar context={context} />
|
||||||
|
</IframeWrapper>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface IframeWrapperProps {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client component that detects if we're in an iframe and conditionally renders children
|
||||||
|
*/
|
||||||
|
export function IframeWrapper({ children }: IframeWrapperProps) {
|
||||||
|
const [isInIframe, setIsInIframe] = React.useState(false);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
// Check if we're running inside an iframe
|
||||||
|
const inIframe = window !== window.parent;
|
||||||
|
setIsInIframe(inIframe);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Don't render children if we're in an iframe (GitBook app preview)
|
||||||
|
if (isInIframe) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
}
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from './AdminToolbar';
|
export * from './AdminToolbar';
|
||||||
|
export * from './IframeWrapper';
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export async function InlineLink(props: InlineProps<DocumentInlineLink>) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
const isExternal = inline.data.ref.kind === 'url';
|
const isExternal = inline.data.ref.kind === 'url';
|
||||||
|
const isMailto = resolved.href.startsWith('mailto:');
|
||||||
const content = (
|
const content = (
|
||||||
<StyledLink
|
<StyledLink
|
||||||
href={resolved.href}
|
href={resolved.href}
|
||||||
@@ -63,7 +64,12 @@ export async function InlineLink(props: InlineProps<DocumentInlineLink>) {
|
|||||||
nodes={inline.nodes}
|
nodes={inline.nodes}
|
||||||
ancestorInlines={[...ancestorInlines, inline]}
|
ancestorInlines={[...ancestorInlines, inline]}
|
||||||
/>
|
/>
|
||||||
{isExternal ? (
|
{isMailto ? (
|
||||||
|
<Icon
|
||||||
|
icon="envelope"
|
||||||
|
className="ml-1 inline size-3 links-accent:text-tint-subtle"
|
||||||
|
/>
|
||||||
|
) : isExternal ? (
|
||||||
<Icon
|
<Icon
|
||||||
icon="arrow-up-right"
|
icon="arrow-up-right"
|
||||||
className="ml-0.5 inline size-3 links-accent:text-tint-subtle"
|
className="ml-0.5 inline size-3 links-accent:text-tint-subtle"
|
||||||
@@ -96,16 +102,24 @@ function InlineLinkTooltipWrapper(props: {
|
|||||||
const { inline, language, resolved, children } = props;
|
const { inline, language, resolved, children } = props;
|
||||||
|
|
||||||
let breadcrumbs = resolved.ancestors ?? [];
|
let breadcrumbs = resolved.ancestors ?? [];
|
||||||
|
const isMailto = resolved.href.startsWith('mailto:');
|
||||||
const isExternal = inline.data.ref.kind === 'url';
|
const isExternal = inline.data.ref.kind === 'url';
|
||||||
const isSamePage = inline.data.ref.kind === 'anchor' && inline.data.ref.page === undefined;
|
const isSamePage = inline.data.ref.kind === 'anchor' && inline.data.ref.page === undefined;
|
||||||
if (isExternal) {
|
|
||||||
|
if (isMailto) {
|
||||||
|
resolved.text = resolved.text.split('mailto:')[1] ?? resolved.text;
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
label: tString(language, 'link_tooltip_email'),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else if (isExternal) {
|
||||||
breadcrumbs = [
|
breadcrumbs = [
|
||||||
{
|
{
|
||||||
label: tString(language, 'link_tooltip_external_link'),
|
label: tString(language, 'link_tooltip_external_link'),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
} else if (isSamePage) {
|
||||||
if (isSamePage) {
|
|
||||||
breadcrumbs = [
|
breadcrumbs = [
|
||||||
{
|
{
|
||||||
label: tString(language, 'link_tooltip_page_anchor'),
|
label: tString(language, 'link_tooltip_page_anchor'),
|
||||||
|
|||||||
@@ -15,12 +15,17 @@ import { getSimplifiedContentType } from '@/lib/files';
|
|||||||
import { resolveContentRef } from '@/lib/references';
|
import { resolveContentRef } from '@/lib/references';
|
||||||
import { tcls } from '@/lib/tailwind';
|
import { tcls } from '@/lib/tailwind';
|
||||||
import { filterOutNullable } from '@/lib/typescript';
|
import { filterOutNullable } from '@/lib/typescript';
|
||||||
|
|
||||||
import type { BlockProps } from '../Block';
|
import type { BlockProps } from '../Block';
|
||||||
import { Blocks } from '../Blocks';
|
import { Blocks } from '../Blocks';
|
||||||
import { FileIcon } from '../FileIcon';
|
import { FileIcon } from '../FileIcon';
|
||||||
import type { TableRecordKV } from './Table';
|
import type { TableRecordKV } from './Table';
|
||||||
import { type VerticalAlignment, getColumnAlignment } from './utils';
|
import {
|
||||||
|
type VerticalAlignment,
|
||||||
|
getColumnAlignment,
|
||||||
|
isContentRef,
|
||||||
|
isDocumentTableImageRecord,
|
||||||
|
isStringArray,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
const alignmentMap: Record<'text-left' | 'text-center' | 'text-right', string> = {
|
const alignmentMap: Record<'text-left' | 'text-center' | 'text-right', string> = {
|
||||||
'text-left': '**:text-left text-left',
|
'text-left': '**:text-left text-left',
|
||||||
@@ -58,18 +63,28 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Because definition and value depends on column, we have to check typing in each case at runtime.
|
||||||
|
// Validation should have been done at the API level, but we can't know typing based on `definition.type`.
|
||||||
|
// OpenAPI types cannot really handle discriminated unions based on a dynamic key.
|
||||||
switch (definition.type) {
|
switch (definition.type) {
|
||||||
case 'checkbox':
|
case 'checkbox': {
|
||||||
|
if (value === null || typeof value !== 'boolean') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
className={tcls('w-5', 'h-5')}
|
className={tcls('w-5', 'h-5')}
|
||||||
checked={value as boolean}
|
checked={value}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
aria-labelledby={ariaLabelledBy}
|
aria-labelledby={ariaLabelledBy}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
case 'rating': {
|
case 'rating': {
|
||||||
const rating = value as number;
|
if (typeof value !== 'number') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const rating = value;
|
||||||
const max = definition.max;
|
const max = definition.max;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -108,15 +123,21 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'number':
|
case 'number': {
|
||||||
|
if (typeof value !== 'number') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Tag
|
<Tag
|
||||||
className={tcls('text-base', 'tabular-nums', 'tracking-tighter')}
|
className={tcls('text-base', 'tabular-nums', 'tracking-tighter')}
|
||||||
aria-labelledby={ariaLabelledBy}
|
aria-labelledby={ariaLabelledBy}
|
||||||
>{`${value}`}</Tag>
|
>{`${value}`}</Tag>
|
||||||
);
|
);
|
||||||
|
}
|
||||||
case 'text': {
|
case 'text': {
|
||||||
// @ts-ignore
|
if (typeof value !== 'string') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const fragment = getNodeFragmentByName(block, value);
|
const fragment = getNodeFragmentByName(block, value);
|
||||||
if (!fragment) {
|
if (!fragment) {
|
||||||
return <Tag className={tcls(['w-full', verticalAlignment])}>{''}</Tag>;
|
return <Tag className={tcls(['w-full', verticalAlignment])}>{''}</Tag>;
|
||||||
@@ -149,8 +170,11 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'files': {
|
case 'files': {
|
||||||
|
if (!isStringArray(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const files = await Promise.all(
|
const files = await Promise.all(
|
||||||
(value as string[]).map((fileId) =>
|
value.map((fileId) =>
|
||||||
context.contentContext
|
context.contentContext
|
||||||
? resolveContentRef(
|
? resolveContentRef(
|
||||||
{
|
{
|
||||||
@@ -221,10 +245,12 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'content-ref': {
|
case 'content-ref': {
|
||||||
const contentRef = value ? (value as ContentRef) : null;
|
if (value === null || !isContentRef(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const resolved =
|
const resolved =
|
||||||
contentRef && context.contentContext
|
value && context.contentContext
|
||||||
? await resolveContentRef(contentRef, context.contentContext, {
|
? await resolveContentRef(value, context.contentContext, {
|
||||||
resolveAnchorText: true,
|
resolveAnchorText: true,
|
||||||
iconStyle: ['mr-2', 'text-tint-subtle'],
|
iconStyle: ['mr-2', 'text-tint-subtle'],
|
||||||
})
|
})
|
||||||
@@ -239,11 +265,11 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
<StyledLink
|
<StyledLink
|
||||||
href={resolved.href}
|
href={resolved.href}
|
||||||
insights={
|
insights={
|
||||||
contentRef
|
value
|
||||||
? {
|
? {
|
||||||
type: 'link_click',
|
type: 'link_click',
|
||||||
link: {
|
link: {
|
||||||
target: contentRef,
|
target: value,
|
||||||
position: SiteInsightsLinkPosition.Content,
|
position: SiteInsightsLinkPosition.Content,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -257,8 +283,11 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'users': {
|
case 'users': {
|
||||||
|
if (!isStringArray(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const resolved = await Promise.all(
|
const resolved = await Promise.all(
|
||||||
(value as string[]).map(async (userId) => {
|
value.map(async (userId) => {
|
||||||
const contentRef: ContentRefUser = {
|
const contentRef: ContentRefUser = {
|
||||||
kind: 'user',
|
kind: 'user',
|
||||||
user: userId,
|
user: userId,
|
||||||
@@ -295,10 +324,13 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'select': {
|
case 'select': {
|
||||||
|
if (!isStringArray(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Tag aria-labelledby={ariaLabelledBy}>
|
<Tag aria-labelledby={ariaLabelledBy}>
|
||||||
<span className={tcls('inline-flex', 'gap-2', 'flex-wrap')}>
|
<span className={tcls('inline-flex', 'gap-2', 'flex-wrap')}>
|
||||||
{(value as string[]).map((selectId) => {
|
{value.map((selectId) => {
|
||||||
const option = definition.options.find(
|
const option = definition.options.find(
|
||||||
(option) => option.value === selectId
|
(option) => option.value === selectId
|
||||||
);
|
);
|
||||||
@@ -329,8 +361,15 @@ export async function RecordColumnValue<Tag extends React.ElementType = 'div'>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
case 'image': {
|
case 'image': {
|
||||||
|
if (!isDocumentTableImageRecord(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const image = context.contentContext
|
const image = context.contentContext
|
||||||
? await resolveContentRef(value as ContentRef, context.contentContext)
|
? await resolveContentRef(
|
||||||
|
'ref' in value ? value.ref : value,
|
||||||
|
context.contentContext
|
||||||
|
)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
|
|||||||
@@ -123,3 +123,35 @@ export function getColumnVerticalAlignment(column: DocumentTableDefinition): Ver
|
|||||||
|
|
||||||
return 'self-center';
|
return 'self-center';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a value is a ContentRef.
|
||||||
|
* @param ref The value to check.
|
||||||
|
* @returns True if the value is a ContentRef, false otherwise.
|
||||||
|
*/
|
||||||
|
export function isContentRef(ref?: DocumentTableRecord['values'][string]): ref is ContentRef {
|
||||||
|
return Boolean(ref && typeof ref === 'object' && 'kind' in ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a value is an array of strings.
|
||||||
|
* @param value The value to check.
|
||||||
|
* @returns True if the value is an array of strings, false otherwise.
|
||||||
|
*/
|
||||||
|
export function isStringArray(value?: DocumentTableRecord['values'][string]): value is string[] {
|
||||||
|
return Array.isArray(value) && value.every((v) => typeof v === 'string');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a value is a DocumentTableImageRecord.
|
||||||
|
* @param value The value to check.
|
||||||
|
* @returns True if the value is a DocumentTableImageRecord, false otherwise.
|
||||||
|
*/
|
||||||
|
export function isDocumentTableImageRecord(
|
||||||
|
value?: DocumentTableRecord['values'][string]
|
||||||
|
): value is DocumentTableImageRecord {
|
||||||
|
if (isContentRef(value) && (value.kind === 'file' || value.kind === 'url')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return Boolean(value && typeof value === 'object' && 'ref' in value && isContentRef(value.ref));
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,13 +80,14 @@ export function Header(props: {
|
|||||||
>
|
>
|
||||||
<HeaderMobileMenu
|
<HeaderMobileMenu
|
||||||
className={tcls(
|
className={tcls(
|
||||||
'lg:hidden',
|
|
||||||
'-ml-2',
|
'-ml-2',
|
||||||
'text-tint-strong',
|
'text-tint-strong',
|
||||||
'theme-bold:text-header-link',
|
'theme-bold:text-header-link',
|
||||||
'hover:bg-tint-hover',
|
'hover:bg-tint-hover',
|
||||||
'hover:theme-bold:bg-header-link/3',
|
'hover:theme-bold:bg-header-link/3',
|
||||||
withVariants === 'generic' ? '' : 'page-no-toc:hidden'
|
withVariants === 'generic'
|
||||||
|
? 'xl:hidden'
|
||||||
|
: 'page-no-toc:hidden lg:hidden'
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<HeaderLogo context={context} />
|
<HeaderLogo context={context} />
|
||||||
|
|||||||
@@ -123,8 +123,7 @@ export async function streamAskQuestion({
|
|||||||
},
|
},
|
||||||
scope: {
|
scope: {
|
||||||
mode: 'default',
|
mode: 'default',
|
||||||
// Include the current site space regardless.
|
currentSiteSpace: context.siteSpace.id,
|
||||||
includedSiteSpaces: [context.siteSpace.id],
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ format: 'document' }
|
{ format: 'document' }
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ export function encodeClientSiteSections(context: GitBookSiteContext, sections:
|
|||||||
for (const item of list) {
|
for (const item of list) {
|
||||||
switch (item.object) {
|
switch (item.object) {
|
||||||
case 'site-section-group': {
|
case 'site-section-group': {
|
||||||
const sections = item.sections
|
const sections = item.sections.map((section) => encodeSection(context, section));
|
||||||
.filter((section) => shouldIncludeSection(context, section))
|
|
||||||
.map((section) => encodeSection(context, section));
|
|
||||||
|
|
||||||
// Skip empty groups
|
// Skip empty groups
|
||||||
if (sections.length === 0) {
|
if (sections.length === 0) {
|
||||||
@@ -74,38 +72,13 @@ function encodeSection(context: GitBookSiteContext, section: SiteSection) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if a section should be included in the list of sections.
|
|
||||||
*/
|
|
||||||
function shouldIncludeSection(context: GitBookSiteContext, section: SiteSection) {
|
|
||||||
if (context.site.id !== 'site_JOVzv') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Testing for a new mode of navigation where the multi-variants section are hidden
|
|
||||||
// if they do not include an equivalent of the current site space.
|
|
||||||
|
|
||||||
// TODO: replace with a proper flag on the section
|
|
||||||
const withNavigateOnlyIfEquivalent = section.id === 'sitesc_4jvEm';
|
|
||||||
|
|
||||||
if (!withNavigateOnlyIfEquivalent) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { siteSpace: currentSiteSpace } = context;
|
|
||||||
if (section.siteSpaces.length === 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return section.siteSpaces.some((siteSpace) =>
|
|
||||||
areSiteSpacesEquivalent(siteSpace, currentSiteSpace)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the best default site space to navigate to for a givent section:
|
* Find the best default site space to navigate to for a givent section:
|
||||||
* 1. If we are on the default, continue on the default.
|
* 1. If we are on the default, continue on the default.
|
||||||
* 2. If a site space has the same path as the current one, return it.
|
* 2. If there are site spaces with the same language as the current, filter by language.
|
||||||
* 3. Otherwise, return the default one.
|
* 3. If a site space has the same path as the current one, return it.
|
||||||
|
* 4. Otherwise, return the default first language match.
|
||||||
|
* 5. Otherwise, return the default one.
|
||||||
*/
|
*/
|
||||||
function findBestTargetURL(context: GitBookSiteContext, section: SiteSection) {
|
function findBestTargetURL(context: GitBookSiteContext, section: SiteSection) {
|
||||||
const { siteSpace: currentSiteSpace } = context;
|
const { siteSpace: currentSiteSpace } = context;
|
||||||
@@ -114,9 +87,15 @@ function findBestTargetURL(context: GitBookSiteContext, section: SiteSection) {
|
|||||||
return getSectionURL(context, section);
|
return getSectionURL(context, section);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bestMatch = section.siteSpaces.find((siteSpace) =>
|
const possibleMatches =
|
||||||
areSiteSpacesEquivalent(siteSpace, currentSiteSpace)
|
section.siteSpaces.filter((siteSpace) =>
|
||||||
);
|
areSiteSpacesSameLanguage(siteSpace, currentSiteSpace)
|
||||||
|
) ?? section.siteSpaces;
|
||||||
|
|
||||||
|
const bestMatch =
|
||||||
|
possibleMatches.find((siteSpace) => areSiteSpacesEquivalent(siteSpace, currentSiteSpace)) ??
|
||||||
|
possibleMatches[0];
|
||||||
|
|
||||||
if (bestMatch) {
|
if (bestMatch) {
|
||||||
return getSiteSpaceURL(context, bestMatch);
|
return getSiteSpaceURL(context, bestMatch);
|
||||||
}
|
}
|
||||||
@@ -130,3 +109,7 @@ function findBestTargetURL(context: GitBookSiteContext, section: SiteSection) {
|
|||||||
function areSiteSpacesEquivalent(siteSpace1: SiteSpace, siteSpace2: SiteSpace) {
|
function areSiteSpacesEquivalent(siteSpace1: SiteSpace, siteSpace2: SiteSpace) {
|
||||||
return siteSpace1.path === siteSpace2.path;
|
return siteSpace1.path === siteSpace2.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function areSiteSpacesSameLanguage(siteSpace1: SiteSpace, siteSpace2: SiteSpace) {
|
||||||
|
return siteSpace1.space.language === siteSpace2.space.language;
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import type { RenderAIMessageOptions } from '../AI';
|
|||||||
import { AIChat } from '../AIChat';
|
import { AIChat } from '../AIChat';
|
||||||
import { AdaptiveVisitorContextProvider } from '../Adaptive';
|
import { AdaptiveVisitorContextProvider } from '../Adaptive';
|
||||||
import { Announcement } from '../Announcement';
|
import { Announcement } from '../Announcement';
|
||||||
import { SpacesDropdown } from '../Header/SpacesDropdown';
|
import { SpacesDropdown, TranslationsDropdown } from '../Header/SpacesDropdown';
|
||||||
import { InsightsProvider } from '../Insights';
|
import { InsightsProvider } from '../Insights';
|
||||||
import { SearchContainer } from '../Search';
|
import { SearchContainer } from '../Search';
|
||||||
import { SiteSectionList, encodeClientSiteSections } from '../SiteSections';
|
import { SiteSectionList, encodeClientSiteSections } from '../SiteSections';
|
||||||
@@ -156,12 +156,20 @@ export function SpaceLayout(props: SpaceLayoutProps) {
|
|||||||
'pr-4',
|
'pr-4',
|
||||||
'lg:flex',
|
'lg:flex',
|
||||||
'grow-0',
|
'grow-0',
|
||||||
'flex-wrap',
|
|
||||||
'dark:shadow-light/1',
|
'dark:shadow-light/1',
|
||||||
'text-base/tight'
|
'text-base/tight',
|
||||||
|
'items-center'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<HeaderLogo context={context} />
|
<HeaderLogo context={context} />
|
||||||
|
{withVariants === 'translations' ? (
|
||||||
|
<TranslationsDropdown
|
||||||
|
context={context}
|
||||||
|
siteSpace={siteSpace}
|
||||||
|
siteSpaces={siteSpaces}
|
||||||
|
className="[&_.button-leading-icon]:block! ml-auto py-2 [&_.button-content]:hidden"
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export const de = {
|
|||||||
pdf_limit_reached_continue: 'Mit ${1} weiteren Seiten erweitern.',
|
pdf_limit_reached_continue: 'Mit ${1} weiteren Seiten erweitern.',
|
||||||
more: 'Mehr',
|
more: 'Mehr',
|
||||||
link_tooltip_external_link: 'Externe Verlinkung zu',
|
link_tooltip_external_link: 'Externe Verlinkung zu',
|
||||||
|
link_tooltip_email: 'E-Mail senden an',
|
||||||
link_tooltip_page_anchor: 'Zum Abschnitt springen',
|
link_tooltip_page_anchor: 'Zum Abschnitt springen',
|
||||||
open_in_new_tab: 'In neuem Tab öffnen',
|
open_in_new_tab: 'In neuem Tab öffnen',
|
||||||
ai_chat_assistant_name: 'GitBook-Assistent',
|
ai_chat_assistant_name: 'GitBook-Assistent',
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export const en = {
|
|||||||
pdf_limit_reached_continue: 'Extend with ${1} more pages.',
|
pdf_limit_reached_continue: 'Extend with ${1} more pages.',
|
||||||
more: 'More',
|
more: 'More',
|
||||||
link_tooltip_external_link: 'External link to',
|
link_tooltip_external_link: 'External link to',
|
||||||
|
link_tooltip_email: 'Send an email to',
|
||||||
link_tooltip_page_anchor: 'Jump to section',
|
link_tooltip_page_anchor: 'Jump to section',
|
||||||
open_in_new_tab: 'Open in new tab',
|
open_in_new_tab: 'Open in new tab',
|
||||||
ai_chat_assistant_name: 'GitBook Assistant',
|
ai_chat_assistant_name: 'GitBook Assistant',
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export const es: TranslationLanguage = {
|
|||||||
pdf_limit_reached_continue: 'Extender con ${1} páginas más.',
|
pdf_limit_reached_continue: 'Extender con ${1} páginas más.',
|
||||||
more: 'Más',
|
more: 'Más',
|
||||||
link_tooltip_external_link: 'Enlace externo a',
|
link_tooltip_external_link: 'Enlace externo a',
|
||||||
|
link_tooltip_email: 'Enviar un correo electrónico a',
|
||||||
link_tooltip_page_anchor: 'Saltar a la sección',
|
link_tooltip_page_anchor: 'Saltar a la sección',
|
||||||
open_in_new_tab: 'Abrir en una nueva pestaña',
|
open_in_new_tab: 'Abrir en una nueva pestaña',
|
||||||
ai_chat_assistant_name: 'Asistente de GitBook',
|
ai_chat_assistant_name: 'Asistente de GitBook',
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ export const fr = {
|
|||||||
pdf_limit_reached_continue: 'Ajouter ${1} pages supplémentaires',
|
pdf_limit_reached_continue: 'Ajouter ${1} pages supplémentaires',
|
||||||
more: 'Plus',
|
more: 'Plus',
|
||||||
link_tooltip_external_link: 'Lien externe vers',
|
link_tooltip_external_link: 'Lien externe vers',
|
||||||
|
link_tooltip_email: 'Envoyer un e-mail à',
|
||||||
link_tooltip_page_anchor: 'Aller à la section',
|
link_tooltip_page_anchor: 'Aller à la section',
|
||||||
open_in_new_tab: 'Ouvrir dans un nouvel onglet',
|
open_in_new_tab: 'Ouvrir dans un nouvel onglet',
|
||||||
ai_chat_assistant_name: 'Assistant GitBook',
|
ai_chat_assistant_name: 'Assistant GitBook',
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export const ja: TranslationLanguage = {
|
|||||||
pdf_limit_reached_continue: 'さらに${1}ページで拡張',
|
pdf_limit_reached_continue: 'さらに${1}ページで拡張',
|
||||||
more: '詳細',
|
more: '詳細',
|
||||||
link_tooltip_external_link: '外部リンク先',
|
link_tooltip_external_link: '外部リンク先',
|
||||||
|
link_tooltip_email: 'メールを送信',
|
||||||
link_tooltip_page_anchor: 'ページ内リンク先',
|
link_tooltip_page_anchor: 'ページ内リンク先',
|
||||||
open_in_new_tab: '新しいタブで開く',
|
open_in_new_tab: '新しいタブで開く',
|
||||||
ai_chat_assistant_name: 'GitBookアシスタント',
|
ai_chat_assistant_name: 'GitBookアシスタント',
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export const nl: TranslationLanguage = {
|
|||||||
pdf_limit_reached_continue: "Verleng met ${1} extra pagina's.",
|
pdf_limit_reached_continue: "Verleng met ${1} extra pagina's.",
|
||||||
more: 'Meer',
|
more: 'Meer',
|
||||||
link_tooltip_external_link: 'Externe link naar',
|
link_tooltip_external_link: 'Externe link naar',
|
||||||
|
link_tooltip_email: 'E-mail versturen naar',
|
||||||
link_tooltip_page_anchor: 'Spring naar sectie',
|
link_tooltip_page_anchor: 'Spring naar sectie',
|
||||||
open_in_new_tab: 'Open in nieuw tabblad',
|
open_in_new_tab: 'Open in nieuw tabblad',
|
||||||
ai_chat_assistant_name: 'GitBook Assistent',
|
ai_chat_assistant_name: 'GitBook Assistent',
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ export const no: TranslationLanguage = {
|
|||||||
pdf_limit_reached_continue: 'Utvid med ${1} flere sider.',
|
pdf_limit_reached_continue: 'Utvid med ${1} flere sider.',
|
||||||
more: 'Mer',
|
more: 'Mer',
|
||||||
link_tooltip_external_link: 'Ekstern lenke til',
|
link_tooltip_external_link: 'Ekstern lenke til',
|
||||||
|
link_tooltip_email: 'Send e-post til',
|
||||||
link_tooltip_page_anchor: 'Hopp til seksjon',
|
link_tooltip_page_anchor: 'Hopp til seksjon',
|
||||||
open_in_new_tab: 'Åpne i ny fane',
|
open_in_new_tab: 'Åpne i ny fane',
|
||||||
ai_chat_assistant_name: 'GitBook-assistent',
|
ai_chat_assistant_name: 'GitBook-assistent',
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ export const pt_br = {
|
|||||||
pdf_limit_reached_continue: 'Extender com mais ${1} páginas.',
|
pdf_limit_reached_continue: 'Extender com mais ${1} páginas.',
|
||||||
more: 'Mais',
|
more: 'Mais',
|
||||||
link_tooltip_external_link: 'Link externo para',
|
link_tooltip_external_link: 'Link externo para',
|
||||||
|
link_tooltip_email: 'Enviar e-mail para',
|
||||||
link_tooltip_page_anchor: 'Pular para a seção',
|
link_tooltip_page_anchor: 'Pular para a seção',
|
||||||
open_in_new_tab: 'Abrir em uma nova guia',
|
open_in_new_tab: 'Abrir em uma nova guia',
|
||||||
ai_chat_assistant_name: 'Assistente do GitBook',
|
ai_chat_assistant_name: 'Assistente do GitBook',
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ export const ru = {
|
|||||||
pdf_limit_reached_continue: 'Расширьте ещё на ${1} страниц.',
|
pdf_limit_reached_continue: 'Расширьте ещё на ${1} страниц.',
|
||||||
more: 'Ещё',
|
more: 'Ещё',
|
||||||
link_tooltip_external_link: 'Внешняя ссылка на',
|
link_tooltip_external_link: 'Внешняя ссылка на',
|
||||||
|
link_tooltip_email: 'Отправить письмо на',
|
||||||
link_tooltip_page_anchor: 'Перейти к разделу',
|
link_tooltip_page_anchor: 'Перейти к разделу',
|
||||||
open_in_new_tab: 'Открыть в новой вкладке',
|
open_in_new_tab: 'Открыть в новой вкладке',
|
||||||
ai_chat_assistant_name: 'GitBook-помощник',
|
ai_chat_assistant_name: 'GitBook-помощник',
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export const zh: TranslationLanguage = {
|
|||||||
pdf_limit_reached_continue: '使用${1}页进行扩展。',
|
pdf_limit_reached_continue: '使用${1}页进行扩展。',
|
||||||
more: '更多',
|
more: '更多',
|
||||||
link_tooltip_external_link: '外部链接到',
|
link_tooltip_external_link: '外部链接到',
|
||||||
|
link_tooltip_email: '发送邮件到',
|
||||||
link_tooltip_page_anchor: '跳转到页面',
|
link_tooltip_page_anchor: '跳转到页面',
|
||||||
open_in_new_tab: '在新标签页中打开',
|
open_in_new_tab: '在新标签页中打开',
|
||||||
ai_chat_assistant_name: 'GitBook 助手',
|
ai_chat_assistant_name: 'GitBook 助手',
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
# @gitbook/react-openapi
|
# @gitbook/react-openapi
|
||||||
|
|
||||||
|
## 1.4.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies [3548fa6]
|
||||||
|
- @gitbook/expr@1.1.1
|
||||||
|
|
||||||
|
## 1.4.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 24f601d: Small optim in resolveTryItPrefillForOperation
|
||||||
|
- Updated dependencies [e1ff17e]
|
||||||
|
- Updated dependencies [8ff1e3b]
|
||||||
|
- @gitbook/expr@1.1.0
|
||||||
|
|
||||||
## 1.4.0
|
## 1.4.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"default": "./dist/index.js"
|
"default": "./dist/index.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version": "1.4.0",
|
"version": "1.4.2",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@gitbook/expr": "workspace:*",
|
"@gitbook/expr": "workspace:*",
|
||||||
|
|||||||
@@ -27,12 +27,16 @@ export function resolveTryItPrefillForOperation(args: {
|
|||||||
prefillInputContext,
|
prefillInputContext,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
// Fixed ExpressionRuntime and resolveTryItPrefillExpression function
|
if (!prefillInputContext) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const runtime = new ExpressionRuntime();
|
const runtime = new ExpressionRuntime();
|
||||||
const resolveTryItPrefillExpression = (expr: string) => {
|
const resolveTryItPrefillExpression = (expr: string) => {
|
||||||
if (!prefillInputContext) return undefined;
|
|
||||||
const parts = parseTemplate(expr);
|
const parts = parseTemplate(expr);
|
||||||
if (!parts.length) return undefined;
|
if (!parts.length) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
return runtime.evaluateTemplate(expr, prefillInputContext);
|
return runtime.evaluateTemplate(expr, prefillInputContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user