Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: version-compare-component #445

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions locale/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,21 @@
"fab": {
"scrollToTop": "Scroll to top",
"goToFeedback": "Was this page helpful?"
},
"versionFilter": {
"yes": "Yes",
"no": "No",
"diffLabel": "Diff filter:",
"diffModeOlderVersion": "Older Version",
"diffModeNewerVersion": "Newer Version",
"introducedInitVersion": "From the beginning",
"introducedVersion": "New in {{version}}",
"type": "Type: ",
"persists": "Persists to cluster: ",
"hintSetVar": "Applies to hint <0>SET_VAR</0>: ",
"default": "Default value: ",
"range": "Range: ",
"possibleValues": "Possible values: ",
"unit": "Unit: "
}
}
16 changes: 16 additions & 0 deletions locale/ja/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,21 @@
"fab": {
"scrollToTop": "トップへ戻る",
"goToFeedback": "このページは役に立ちましたか?"
},
"versionFilter": {
"yes": "はい",
"no": "いいえ",
"diffLabel": "差分フィルタ:",
"diffModeOlderVersion": "古いバージョン",
"diffModeNewerVersion": "新しいバージョン",
"introducedInitVersion": "最初から",
"introducedVersion": "{{version}} から新しい",
"type": "タイプ:",
"persists": "クラスターに保持:",
"hintSetVar": "ヒント <0>SET_VAR</0> に適用:",
"default": "デフォルト値:",
"range": "範囲:",
"possibleValues": "可能な値:",
"unit": "単位:"
}
}
16 changes: 16 additions & 0 deletions locale/zh/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,5 +114,21 @@
"fab": {
"scrollToTop": "回到顶部",
"goToFeedback": "文档内容是否有帮助?"
},
"versionFilter": {
"yes": "是",
"no": "否",
"diffLabel": "差异过滤:",
"diffModeOlderVersion": "较旧版本",
"diffModeNewerVersion": "较新版本",
"introducedInitVersion": "初始版本引入",
"introducedVersion": "从 {{version}} 版本开始引入",
"type": "类型:",
"persists": "是否持久化到集群:",
"hintSetVar": "是否受 Hint <0>SET_VAR</0> 控制:",
"default": "默认值:",
"range": "范围:",
"possibleValues": "可选值:",
"unit": "单位:"
}
}
21 changes: 13 additions & 8 deletions src/components/Layout/MDXContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { Locale, PathConfig, FrontMatter, BuildType } from "static/Type";
import { useTotalContributors } from "components/Avatar/Contributors";
import replaceInternalHref from "utils/anchor";
import { Pre } from "components/MDXComponents/Pre";
import { MdxContext } from "context/MdxContext";

export default function MDXContent(props: {
data: any;
Expand Down Expand Up @@ -74,15 +75,19 @@ export default function MDXContent(props: {
availIn={availIn}
/>
)}
<MDXProvider
components={{
...MDXConponents,
Link,
pre: Pre,
}}
<MdxContext.Provider
value={{pathConfig}}
>
<MDXRenderer>{data}</MDXRenderer>
</MDXProvider>
<MDXProvider
components={{
...MDXConponents,
Link,
pre: Pre,
}}
>
<MDXRenderer>{data}</MDXRenderer>
</MDXProvider>
</MdxContext.Provider>
</Box>
</Container>
);
Expand Down
21 changes: 21 additions & 0 deletions src/components/MDXComponents/MDLink.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as React from "react";

import { MdxContext } from "context/MdxContext";
import { Link } from "gatsby-plugin-react-i18next";
import { Locale } from "static/Type";

export function MDLink(props: {
url: string;
children?: any;
}) {
const mdxContextData = React.useContext(MdxContext);
const { pathConfig } = mdxContextData;
const {url} = props;
const localeURL = pathConfig.locale === Locale.en ? "" : "/" + pathConfig.locale;
const relativeURL = url.startsWith("/") ? url : "/" + url;
const realURL = localeURL + "/" + pathConfig.repo + "/" + pathConfig.version + relativeURL;

return (
<Link to={realURL}>{props.children}</Link>
)
}
229 changes: 229 additions & 0 deletions src/components/MDXComponents/VersionVarsFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import * as React from "react";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { Link, Trans, useI18next } from "gatsby-plugin-react-i18next";
import { Container, Autocomplete, TextField, ToggleButtonGroup, ToggleButton, Card, CardContent, Chip, Accordion, AccordionDetails, AccordionSummary } from '@mui/material';
import { MDLink } from "./MDLink";

type ScopeType = "SESSION" | "GLOBAL" | "BOTH";

export function VersionVarsFilter(props: {
versions: string;
children?: React.FC[];
}) {

const [startVersion, setStartVersion] = React.useState<string>("");
const [endVersion, setEndVersion] = React.useState<string>("");

const {
versions = "",
children = [],
} = props;

const versionArray = versions.split(",");

const compareVersions = (ver1: string, ver2: string) => {
if (ver1.startsWith("v")) {
ver1 = ver1.substring(1);
}

if (ver2.startsWith("v")) {
ver2 = ver2.substring(1);
}

const ver1Array = ver1.split(".");
const ver2Array = ver2.split(".");

if (ver1Array.length !== 3 || ver2Array.length !== 3) {
console.log(ver1, ver2);
throw new Error("Version format is incorrect");
}

for (let i = 0; i < ver1Array.length; i++) {
if (parseInt(ver1Array[i]) > parseInt(ver2Array[i])) {
return 1;
} else if (parseInt(ver1Array[i]) < parseInt(ver2Array[i])) {
return -1;
}
}
return 0;
}

versionArray.sort((a, b) => -compareVersions(a, b));

const MIN_VERSION = "v0.0.0";
const MAX_VERSION = "v999.999.999";
const filterVersion = (versions: string[], includeEqual: boolean, left?: string|null, right?: string|null) => {
return versions.filter((version) => {
if (left === undefined || left === null || left === "") {
left = MIN_VERSION;
}

if (right === undefined || right === null || right === "") {
right = MAX_VERSION;
}

let leftCompare = compareVersions(version, left);
let rightCompare = compareVersions(right, version);
let standard = includeEqual ? 0 : 1;

return leftCompare >= standard && rightCompare >= standard;
});
}

const filterVersionVars = (children: any[]) => {
if (!Array.isArray(children)) {
children = [children];
}

return children.map((child) => {
if (child.props?.mdxType !== VersionVars.name) {
// It's not of the filter scope, skip it.
return child;
}

if (startVersion === "" || endVersion === "") {
// No version is selected, skip it.
return <VersionVars {...child.props} />;
}

let introducedVersion = child.props.introducedVersion;
if (!introducedVersion) {
introducedVersion = "v0.0.1";
}

if (compareVersions(startVersion!, introducedVersion) <= 0 &&
compareVersions(introducedVersion, endVersion!) <= 0) {
return (
<VersionVars {...child.props} />
)
}

return "";
});
}

return (
<div>
<Stack
id="search-area"
direction="row"
alignItems="center"
sx={{
width: "100%",
justifyContent: "space-between",
flexDirection: {
xs: "column-reverse",
md: "row",
},
}}
>
<Stack
id="compare-filter"
direction="row"
alignItems="center"
>
<div><Trans i18nKey={`versionFilter.diffLabel`}/></div>
<Autocomplete
disablePortal
id="start-version"
value={startVersion}
options={filterVersion(versionArray, false, MIN_VERSION, endVersion)}
sx={{ width: 200, margin: 1 }}
onChange={(_, newVersion) => {
setStartVersion(newVersion ? newVersion : "")
}}
renderInput={(params) => <TextField {...params} label={<Trans i18nKey={`versionFilter.diffModeOlderVersion`}/>} />}
/>

<Autocomplete
disablePortal
id="end-version"
value={endVersion}
options={filterVersion(versionArray, false, startVersion, MAX_VERSION)}
sx={{ width: 200, margin: 1 }}
onChange={(_, newVersion) => {setEndVersion(newVersion ? newVersion : "")}}
renderInput={(params) => <TextField {...params} label={<Trans i18nKey={`versionFilter.diffModeNewerVersion`}/>} />}
/>
</Stack>
</Stack>

<Stack
id="vars-area"
direction="column"
sx={{
width: "100%",
justifyContent: "space-between",
flexDirection: {
xs: "column-reverse",
md: "column",
},
}}
>
{filterVersionVars(children)}
</Stack>
</div>
);
}


export function VersionVars(props: {
name: string;
scope: ScopeType;
type?: string;
applyHint: string;
defaultValue: string;
persists?: string;
introducedVersion?: string;
possibleValues?: string;
range?: string;
unit?: string;
children?: any;
}) {

const INIT_VERSION = "v0.0.1"
const {
name = "",
introducedVersion = INIT_VERSION,
scope = "GLOBAL",
type = "",
applyHint = "false",
defaultValue = "",
children = [],
possibleValues = "",
range = "",
unit = "",
} = props;

const yesOrNoI18n = (value: string) => {
return value === "true" ? <Trans i18nKey={`versionFilter.yes`}/> : <Trans i18nKey={`versionFilter.no`}/>;
}

return (
<Stack sx={{ minWidth: 275, flexShrink: 0, width: "100%", marginTop: "20px"}}>
<Stack direction="column" spacing={1}>
<Stack direction="row" spacing={1}>
<Typography variant="h4" component="div" color="black"> <a id={name} href={"#"+name}>{name}</a> </Typography>
<Stack direction="row" spacing={1} sx={{alignItems: "center"}}>
{scope === "SESSION" || scope === "BOTH" ? <Chip label="SESSION" size="small" color="primary" /> : null}
{scope === "GLOBAL" || scope === "BOTH" ? <Chip label="GLOBAL" size="small" color="success" /> : null}
</Stack>
</Stack>
<Typography sx={{ mb: 1.5 }} color="text.secondary">
{ introducedVersion === INIT_VERSION ?
<Trans i18nKey={`versionFilter.introducedInitVersion`}/> :
<Trans i18nKey={`versionFilter.introducedVersion`} values={{version: introducedVersion}}/> }
</Typography>
{type === "" ? "" : <Typography> <Trans i18nKey={`versionFilter.type`}/> {type} </Typography>}
{props.persists === undefined ? "" : <Typography> <Trans i18nKey={`versionFilter.persists`}/> {yesOrNoI18n(props.persists)}</Typography>}
<Typography> <Trans i18nKey={`versionFilter.hintSetVar`} components={[<MDLink url="/optimizer-hints#set_varvar_namevar_value"/>]}/> {yesOrNoI18n(applyHint)} </Typography>
<Typography> <Trans i18nKey={`versionFilter.default`}/> {defaultValue} </Typography>
{range === "" ? "" : <Typography> <Trans i18nKey={`versionFilter.range`}/> {range} </Typography>}
{possibleValues === "" ? "" : <Typography> <Trans i18nKey={`versionFilter.possibleValues`}/> {possibleValues} </Typography>}
{unit === "" ? "" : <Typography> <Trans i18nKey={`versionFilter.unit`}/> {unit} </Typography>}
</Stack>

{children}
</Stack>
);
}
3 changes: 3 additions & 0 deletions src/components/MDXComponents/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ export {
DocHomeCard,
} from "components/MDXComponents/DocHome";
export { MDSvgIcon } from "components/MDXComponents/MDSvgIcon";
export {
VersionVarsFilter,
} from "components/MDXComponents/VersionVarsFilter";
17 changes: 17 additions & 0 deletions src/context/MdxContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from "react";
import { Locale, PathConfig, Repo } from "static/Type";

interface IDefalutMdxContext {
pathConfig: PathConfig;
}

export const DefalutMdxContext: IDefalutMdxContext = {
pathConfig: {
repo: Repo.tidb,
locale: Locale.en,
branch: "dev",
version: null
}
};

export const MdxContext = React.createContext(DefalutMdxContext);
1 change: 0 additions & 1 deletion src/templates/DocTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export default function DocTemplate({
}, [tableOfContents.items]);

const stableBranch = getStable(pathConfig.repo);

const { language } = useI18next();

return (
Expand Down