未验证 提交 cc2a69e7 编写于 作者: G Guillaume 提交者: GitHub

feat: add copy build version link in footer (#1007)

上级 0ec302aa
...@@ -18879,6 +18879,14 @@ ...@@ -18879,6 +18879,14 @@
"csstype": "^2.2.0" "csstype": "^2.2.0"
} }
}, },
"@types/react-copy-to-clipboard": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/@types/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.0.tgz",
"integrity": "sha512-faUg6Kx3Dfv0MBIcs+xzIptlRtjEVSaNjqyC14YAp4UwSiTHghnKtBOt9ERRTZZJfoJgnw10tomVaqG86GzdAw==",
"requires": {
"@types/react": "*"
}
},
"@types/react-dom": { "@types/react-dom": {
"version": "16.9.8", "version": "16.9.8",
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz",
...@@ -21151,6 +21159,14 @@ ...@@ -21151,6 +21159,14 @@
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
"dev": true "dev": true
}, },
"copy-to-clipboard": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz",
"integrity": "sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==",
"requires": {
"toggle-selection": "^1.0.6"
}
},
"copy-webpack-plugin": { "copy-webpack-plugin": {
"version": "6.0.2", "version": "6.0.2",
"resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.0.2.tgz", "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.0.2.tgz",
...@@ -27801,6 +27817,15 @@ ...@@ -27801,6 +27817,15 @@
"prop-types": "^15.7.2" "prop-types": "^15.7.2"
} }
}, },
"react-copy-to-clipboard": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.3.tgz",
"integrity": "sha512-9S3j+m+UxDZOM0Qb8mhnT/rMR0NGSrj9A/073yz2DSxPMYhmYFBMYIdI2X4o8AjOjyFsSNxDRnCX6s/gRxpriw==",
"requires": {
"copy-to-clipboard": "^3",
"prop-types": "^15.5.8"
}
},
"react-dom": { "react-dom": {
"version": "16.13.1", "version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
...@@ -30414,6 +30439,11 @@ ...@@ -30414,6 +30439,11 @@
"repeat-string": "^1.6.1" "repeat-string": "^1.6.1"
} }
}, },
"toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
"integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
},
"toidentifier": { "toidentifier": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"@popperjs/core": "2.4.2", "@popperjs/core": "2.4.2",
"@questdb/sql-grammar": "1.0.7", "@questdb/sql-grammar": "1.0.7",
"@types/react": "16.9.35", "@types/react": "16.9.35",
"@types/react-copy-to-clipboard": "5.0.0",
"@types/react-dom": "16.9.8", "@types/react-dom": "16.9.8",
"@types/react-redux": "7.1.9", "@types/react-redux": "7.1.9",
"@types/react-transition-group": "4.4.0", "@types/react-transition-group": "4.4.0",
...@@ -43,6 +44,7 @@ ...@@ -43,6 +44,7 @@
"jquery": "3.5.1", "jquery": "3.5.1",
"react": "16.13.1", "react": "16.13.1",
"react-ace": "9.0.0", "react-ace": "9.0.0",
"react-copy-to-clipboard": "5.0.3",
"react-dom": "16.13.1", "react-dom": "16.13.1",
"react-popper": "2.2.3", "react-popper": "2.2.3",
"react-redux": "7.2.0", "react-redux": "7.2.0",
......
import React, { createContext, PropsWithChildren } from "react"
import * as QuestDB from "utils/questdb"
const questClient = new QuestDB.Client()
type Props = {}
type ContextProps = {
quest: QuestDB.Client
}
const defaultValues = {
quest: questClient,
}
export const QuestContext = createContext<ContextProps>(defaultValues)
export const QuestProvider = ({ children }: PropsWithChildren<Props>) => {
return (
<QuestContext.Provider
value={{
quest: questClient,
}}
>
{children}
</QuestContext.Provider>
)
}
export * from "./QuestProvider"
...@@ -23,7 +23,13 @@ ...@@ -23,7 +23,13 @@
******************************************************************************/ ******************************************************************************/
import { Range } from "ace-builds" import { Range } from "ace-builds"
import React, { useCallback, useEffect, useRef, useState } from "react" import React, {
useCallback,
useContext,
useEffect,
useRef,
useState,
} from "react"
import ReactAce from "react-ace" import ReactAce from "react-ace"
import { useDispatch, useSelector } from "react-redux" import { useDispatch, useSelector } from "react-redux"
import ResizeObserver from "resize-observer-polyfill" import ResizeObserver from "resize-observer-polyfill"
...@@ -48,8 +54,7 @@ import { ...@@ -48,8 +54,7 @@ import {
savePreferences, savePreferences,
toTextPosition, toTextPosition,
} from "./utils" } from "./utils"
import { QuestContext } from "providers"
const quest = new QuestDB.Client()
const Content = styled(PaneContent)` const Content = styled(PaneContent)`
position: relative; position: relative;
...@@ -76,6 +81,7 @@ enum Command { ...@@ -76,6 +81,7 @@ enum Command {
} }
const Ace = () => { const Ace = () => {
const { quest } = useContext(QuestContext)
const [request, setRequest] = useState<Request | undefined>() const [request, setRequest] = useState<Request | undefined>()
const [value, setValue] = useState("") const [value, setValue] = useState("")
const aceEditor = useRef<ReactAce | null>(null) const aceEditor = useRef<ReactAce | null>(null)
...@@ -93,7 +99,7 @@ const Ace = () => { ...@@ -93,7 +99,7 @@ const Ace = () => {
dispatch(actions.query.stopRunning()) dispatch(actions.query.stopRunning())
setRequest(undefined) setRequest(undefined)
} }
}, [dispatch, request, running]) }, [request, quest, dispatch, running])
useEffect(() => { useEffect(() => {
if (!aceEditor.current) { if (!aceEditor.current) {
...@@ -192,7 +198,7 @@ const Ace = () => { ...@@ -192,7 +198,7 @@ const Ace = () => {
dispatch(actions.query.stopRunning()) dispatch(actions.query.stopRunning())
} }
} }
}, [dispatch, running]) }, [quest, dispatch, running])
useEffect(() => { useEffect(() => {
if (!aceEditor.current) { if (!aceEditor.current) {
......
import { QuestContext } from "providers"
import React, { useContext, useEffect, useState } from "react"
import styled from "styled-components"
import * as QuestDB from "utils/questdb"
import { CopyToClipboard } from "react-copy-to-clipboard"
import { ClipboardCopy } from "@styled-icons/heroicons-outline/ClipboardCopy"
import { SecondaryButton } from "components"
import { formatVersion } from "./services"
const Wrapper = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
& > :not(:last-child) {
margin-right: 1rem;
}
`
const CopyButton = styled(SecondaryButton)`
& > :not(:last-child) {
margin-right: 1rem;
}
`
const BuildVersion = () => {
const { quest } = useContext(QuestContext)
const [buildVersion, setBuildVersion] = useState("")
useEffect(() => {
void quest.queryRaw("select build", { limit: "0,1000" }).then((result) => {
if (result.type === QuestDB.Type.DQL) {
if (result.count === 1) {
setBuildVersion(result.dataset[0][0])
}
}
})
})
const version = formatVersion(buildVersion)
return (
<Wrapper>
<CopyToClipboard text={buildVersion}>
<CopyButton title="Copy Build Version">
<span>{version}</span>
<ClipboardCopy size="18px" />
</CopyButton>
</CopyToClipboard>
</Wrapper>
)
}
export default BuildVersion
const buildVersionRegex = /Build Information: (QuestDB [0-9A-Za-z.]*),/
export const formatVersion = (value: string) => {
const matches = buildVersionRegex.exec(value)
return matches ? matches[1] : ""
}
...@@ -31,7 +31,8 @@ import { Github } from "@styled-icons/remix-fill/Github" ...@@ -31,7 +31,8 @@ import { Github } from "@styled-icons/remix-fill/Github"
import { Link, Text, TransitionDuration } from "components" import { Link, Text, TransitionDuration } from "components"
import { selectors } from "store" import { selectors } from "store"
import GithubBanner from "../GithubBanner" import GithubBanner from "./GithubBanner"
import BuildVersion from "./BuildVersion"
const Wrapper = styled.div` const Wrapper = styled.div`
position: absolute; position: absolute;
...@@ -43,17 +44,21 @@ const Wrapper = styled.div` ...@@ -43,17 +44,21 @@ const Wrapper = styled.div`
padding-left: 45px; padding-left: 45px;
` `
const Copyright = styled.div` const LeftContainer = styled.div`
display: flex; display: flex;
padding-left: 1rem; padding-left: 1rem;
align-items: center; align-items: center;
flex: 1; flex: 1;
` `
const Icons = styled.div` const RightContainer = styled.div`
display: flex; display: flex;
padding-right: 1rem; padding-right: 1rem;
align-items: center; align-items: center;
& > *:not(:last-child) {
margin-right: 1rem;
}
` `
const GithubBannerTransition = createGlobalStyle` const GithubBannerTransition = createGlobalStyle`
...@@ -92,13 +97,13 @@ const Footer = () => { ...@@ -92,13 +97,13 @@ const Footer = () => {
return ( return (
<Wrapper id="footer"> <Wrapper id="footer">
<GithubBannerTransition /> <LeftContainer>
<Copyright>
<Text color="draculaForeground"> <Text color="draculaForeground">
Copyright &copy; 2014-{new Date().getFullYear()} QuestDB Copyright &copy; 2014-{new Date().getFullYear()} QuestDB
</Text> </Text>
</Copyright> </LeftContainer>
<Icons> <RightContainer>
<BuildVersion />
<Link <Link
color="draculaForeground" color="draculaForeground"
hoverColor="draculaCyan" hoverColor="draculaCyan"
...@@ -108,7 +113,9 @@ const Footer = () => { ...@@ -108,7 +113,9 @@ const Footer = () => {
> >
<Github size="18px" /> <Github size="18px" />
</Link> </Link>
</Icons> </RightContainer>
<GithubBannerTransition />
<CSSTransition <CSSTransition
classNames="github-banner" classNames="github-banner"
in={showBanner && githubBanner} in={showBanner && githubBanner}
......
...@@ -37,6 +37,7 @@ import Result from "../Result" ...@@ -37,6 +37,7 @@ import Result from "../Result"
import SideMenu from "../SideMenu" import SideMenu from "../SideMenu"
import Schema from "../Schema" import Schema from "../Schema"
import Sidebar from "../Sidebar" import Sidebar from "../Sidebar"
import { QuestProvider } from "providers"
const Top = styled.div` const Top = styled.div`
position: relative; position: relative;
...@@ -61,7 +62,7 @@ const Layout = () => { ...@@ -61,7 +62,7 @@ const Layout = () => {
}, []) }, [])
return ( return (
<> <QuestProvider>
<Sidebar /> <Sidebar />
<Footer /> <Footer />
{consoleNode && {consoleNode &&
...@@ -93,7 +94,7 @@ const Layout = () => { ...@@ -93,7 +94,7 @@ const Layout = () => {
{notificationsNode && createPortal(<Notifications />, notificationsNode)} {notificationsNode && createPortal(<Notifications />, notificationsNode)}
{sideMenuNode && createPortal(<SideMenu />, sideMenuNode)} {sideMenuNode && createPortal(<SideMenu />, sideMenuNode)}
{modalNode && createPortal(<Modal />, modalNode)} {modalNode && createPortal(<Modal />, modalNode)}
</> </QuestProvider>
) )
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册