Skip to content

Commit

Permalink
Merge pull request #118 from metrico/feature-resize
Browse files Browse the repository at this point in the history
Added resizable Split and Query editors #109 #110
  • Loading branch information
jacovinus authored Nov 24, 2022
2 parents 5154022 + 67352e9 commit 661331d
Show file tree
Hide file tree
Showing 7 changed files with 358 additions and 77 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"react-flot": "^1.3.0",
"react-query": "^3.39.2",
"react-redux": "^7.2.6",
"react-resizable": "^3.0.4",
"react-responsive": "^9.0.0-beta.6",
"react-router-dom": "^6.2.1",
"react-table": "7.7.0",
Expand Down Expand Up @@ -102,6 +103,7 @@
"@babel/preset-env": "^7.16.11",
"@babel/preset-react": "^7.16.7",
"@types/react-redux": "^7.1.24",
"@types/react-resizable": "^3.0.3",
"babel-loader": "^8.2.3",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-class-properties": "^6.24.1",
Expand Down
71 changes: 47 additions & 24 deletions src/components/LabelBrowser/components/QueryBar.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**React */
import { useState, useEffect, useMemo } from "react";
import { useState, useEffect, useRef, useMemo } from "react";
import { useLocation } from "react-router-dom";
import { useSelector, useDispatch } from "react-redux";
/**npm */
Expand Down Expand Up @@ -73,14 +73,17 @@ export const QueryBar = (props) => {
queryHistory,
start,
stop,
isSplit
} = useSelector((store) => store);
const panelQuery = useSelector((store) => store[name]);
const isTabletOrMobile = useMediaQuery({ query: "(max-width: 914px)" });
const isTabletOrMobile = useMediaQuery({ query: "(max-width: 864px)" });
const [queryInput, setQueryInput] = useState(data.expr);
const [queryValid, setQueryValid] = useState(false);
const [queryValue, setQueryValue] = useState(queryInit(data.expr));
const [open, setOpen] = useState(false);

const wrapperRef = useRef(null)
const labelsButtonRef = useRef(null)
const buttonsContainerRef = useRef(null)
useEffect(() => {});
const saveUrl = localUrl();
const expr = useMemo(() => {
Expand Down Expand Up @@ -203,6 +206,15 @@ export const QueryBar = (props) => {
function onClose() {
showQuerySettings();
}
const getMaxWidth = () => {
const labelButtonWidth = !isNaN(labelsButtonRef?.current?.clientWidth) ? labelsButtonRef?.current?.clientWidth : 0;
const buttonsContainerWidth = !isNaN(buttonsContainerRef?.current?.clientWidth) ? buttonsContainerRef?.current?.clientWidth : 0;
if (isSplit || isTabletOrMobile) {
return 0;
} else {
return ( labelButtonWidth + buttonsContainerWidth + 5)
}
}
return (
!isEmbed && (
<div
Expand All @@ -211,7 +223,7 @@ export const QueryBar = (props) => {
`}
>
<ThemeProvider theme={themes[theme]}>
<MobileTopQueryMenu>
<MobileTopQueryMenu isSplit={isSplit}>
<div
className={css`
display: flex;
Expand All @@ -238,29 +250,40 @@ export const QueryBar = (props) => {
/>
</MobileTopQueryMenu>
<QueryBarContainer>
<ShowLabelsButton {...props} />

<QueryEditor
onQueryChange={handleQueryChange}
defaultValue={expr || ""}
value={queryValue}
onKeyDown={handleInputKeyDown}
/>

<HistoryButton
queryLength={queryHistory.length}
handleHistoryClick={handleHistoryClick}
/>
{!isSplit && <span ref={labelsButtonRef}><ShowLabelsButton {...props} /></span>}
<div
style={{ flex: 1, maxWidth: `calc(100% - ${getMaxWidth()}px)` }}
ref={wrapperRef}
>
<QueryEditor
onQueryChange={handleQueryChange}
defaultValue={expr || ""}
value={queryValue}
isSplit={isSplit}
wrapperRef={wrapperRef?.current?.clientWidth}
onKeyDown={handleInputKeyDown}
/>
</div>
{!isSplit && (
<div style={{ display: "flex", flex: "0" }} ref={buttonsContainerRef}>
<HistoryButton
queryLength={queryHistory.length}
handleHistoryClick={handleHistoryClick}
/>

<ShowLogsButton
disabled={!queryValid}
onClick={onSubmit}
isMobile={false}
/>
<ShowLogsButton
disabled={!queryValid}
onClick={onSubmit}
isMobile={false}
/>
</div>
)}
</QueryBarContainer>

{!isTabletOrMobile && <QueryTypeBar {...props} />}
{isTabletOrMobile && (
{!isTabletOrMobile && !isSplit && (
<QueryTypeBar {...props} />
)}
{(isTabletOrMobile || isSplit) && (
<QuerySetting
{...props}
open={open}
Expand Down
55 changes: 26 additions & 29 deletions src/components/LabelBrowser/components/styled/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import styled from "@emotion/styled"
import styled from "@emotion/styled";

import HistoryIcon from "@mui/icons-material/History";
import { BtnSmall } from "../../../../theme/styles/Button";
Expand All @@ -12,10 +12,10 @@ export const HistoryIconStyled = styled(HistoryIcon)`
export const HistoryButtonStyled = styled(BtnSmall)`
background: none;
margin-left: 5px;
color: ${(props)=> props.theme.textColor};
color: ${(props) => props.theme.textColor};
background: ${(props) => props.theme.buttonDefault};
border:1px solid ${(props)=>props.theme.buttonBorder};
height:28px;
border: 1px solid ${(props) => props.theme.buttonBorder};
height: 28px;
span {
margin-left: 5px;
}
Expand All @@ -26,10 +26,10 @@ export const HistoryButtonStyled = styled(BtnSmall)`

export const ShowLabelsBtn = styled(BtnSmall)`
background: ${({ theme }) => theme.buttonDefault};
border:1px solid ${(props)=>props.theme.buttonBorder};
border: 1px solid ${(props) => props.theme.buttonBorder};
text-overflow: ellipsis;
transition: 0.25s all;
padding-left:6px;
padding-left: 6px;
justify-content: flex-start;
color: ${({ theme }) => theme.textColor};
height: 28px;
Expand All @@ -46,29 +46,29 @@ export const ShowLabelsBtn = styled(BtnSmall)`
export const QueryBarContainer = styled.div`
display: flex;
padding: 6px;
margin-top:5px;
margin-top: 5px;
margin-left: 0px;
background: ${({ theme }) => theme.widgetContainer};
flex-wrap: wrap;
border-radius: 3px;
`;
export const ShowLogsBtn = styled(BtnSmall)`
background: ${(props) => props.theme.primaryDark};
border:1px solid ${(props)=>props.theme.buttonBorder};
border: 1px solid ${(props) => props.theme.buttonBorder};
color: ${(props) => props.theme.buttonText};
margin-left: 5px;
transition: 0.25s all;
justify-content: center;
padding: 3px 12px;
height:28px;
height: 28px;
&:hover {
background: ${(props) => props.theme.primaryLight};
}
&:disabled {
background: ${(props) => props.theme.buttonDefault};
border:1px solid ${(props)=>props.theme.buttonBorder};
border: 1px solid ${(props) => props.theme.buttonBorder};
cursor: not-allowed;
color: ${props => props.theme.textColor};
color: ${(props) => props.theme.textColor};
}
@media screen and (max-width: 864px) {
display: ${(props) => (props.isMobile ? "flex" : "none")};
Expand All @@ -80,35 +80,33 @@ export const ShowLogsBtn = styled(BtnSmall)`
export const ShowSettingsBtn = styled(BtnSmall)`
background: none;
margin-left: 5px;
color: ${(props)=> props.theme.textColor};
color: ${(props) => props.theme.textColor};
background: ${(props) => props.theme.buttonDefault};
border:1px solid ${(props)=>props.theme.buttonBorder};
height:28px;
border: 1px solid ${(props) => props.theme.buttonBorder};
height: 28px;
span {
margin-left: 5px;
}
@media screen and (max-width: 864px) {
display: ${(props) => (props.isMobile ? "flex" : "none")};
}
display: ${(props) => (props.isMobile || props.isSplit ? "flex" : "none")};
`;

export const MobileTopQueryMenu = styled.div`
display: none;
display: ${(props) =>
props.isSplit || props.dataSourceType === "flux" ? "flex" : "none"};
@media screen and (max-width: 864px) {
display: flex;
justify-content: space-between
justify-content: space-between;
}
`;



export const InputGroup = styled.div`
display: flex;
flex:1;
align-items:center;
justify-content:space-between;
flex: 1;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
margin-right:10px;
margin-right: 10px;
`;
export const InlineGroup = styled.div`
display: flex;
Expand All @@ -120,7 +118,6 @@ export const SettingCont = styled.div`
flex: 1;
flex-direction: column;
background: ${({ theme }) => theme.widgetContainer};
`;

Expand All @@ -129,9 +126,9 @@ export const SettingsInputContainer = styled.div`
display: flex;
flex-direction: column;
flex: 1;
.options-input{
margin:10px;
display:flex;
.options-input {
margin: 10px;
display: flex;
}
`;

Expand Down
2 changes: 1 addition & 1 deletion src/components/Panel/Panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const PanelCont = styled.div`
display: flex;
flex-direction: column;
flex: 1;
width: ${(props) => (props.isSplit ? "50%" : "100%")};
width: 100%;
`;
// Panel should have injected data
export default function Panel(props) {
Expand Down
111 changes: 111 additions & 0 deletions src/plugins/ResizableBox/ResiableBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import { ResizableBox as ReactResizableBox } from "react-resizable";
import { css, cx } from "@emotion/css";
import { useSelector } from "react-redux";

interface ResizableBoxProps {
height: number;
minHeight: number;
maxHeight: number;
width: number;
minWidth: number;
maxWidth: number;
children: any;
handle: any;
axis: Axis;
resizeHandles?: Array<ResizeHandleAxis>
onResize: any;
className: string;
}
type Axis = 'both' | 'x' | 'y' | undefined
type ResizeHandleAxis = 's' | 'w' | 'e' | 'n' | 'sw' | 'nw' | 'se' | 'ne';

const getStyles = (theme: string): any => {
return {
"react-resizable": css`
position: relative;
`,
"react-resizable-handle": css`
position: absolute;
width: 20px;
height: 20px;
background-repeat: no-repeat;
background-origin: content-box;
box-sizing: border-box;
filter: ${theme !== 'dark' ? 'none' : 'invert(100%)'};
background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA2IDYiIHN0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiNmZmZmZmYwMCIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI2cHgiIGhlaWdodD0iNnB4Ij48ZyBvcGFjaXR5PSIwLjMwMiI+PHBhdGggZD0iTSA2IDYgTCAwIDYgTCAwIDQuMiBMIDQgNC4yIEwgNC4yIDQuMiBMIDQuMiAwIEwgNiAwIEwgNiA2IEwgNiA2IFoiIGZpbGw9IiMwMDAwMDAiLz48L2c+PC9zdmc+");
background-position: bottom right;
padding: 0 3px 3px 0;
`,
"react-resizable-handle-sw": css`
bottom: 0;
left: 0;
cursor: sw-resize;
transform: rotate(90deg);
`,
"react-resizable-handle-se": css`
bottom: 0;
right: 0;
cursor: se-resize;
`,
"react-resizable-handle-nw": css`
top: 0;
left: 0;
cursor: nw-resize;
transform: rotate(180deg);
`,
"react-resizable-handle-ne": css`
top: 0;
right: 0;
cursor: ne-resize;
transform: rotate(270deg);
`,
"react-resizable-handle-w": css`
top: 50%;
margin-top: -10px;
cursor: ew-resize;
left: 0;
transform: rotate(135deg);
`,
"react-resizable-handle-e": css`
top: 50%;
margin-top: -10px;
cursor: ew-resize;
right: 0;
transform: rotate(315deg);
`,
"react-resizable-handle-n": css`
left: 50%;
margin-left: -10px;
cursor: ns-resize;
top: 0;
transform: rotate(225deg);
`,
"react-resizable-handle-s": css`
left: 50%;
margin-left: -10px;
cursor: ns-resize;
bottom: 0;
transform: rotate(45deg);
`
}};
export function ResizableBox(props: ResizableBoxProps) {

const storeTheme = useSelector(({ theme }: any) => theme);
const { height, width, children, minWidth, maxWidth, minHeight, maxHeight, resizeHandles, onResize, axis, className } = props;
const styles = getStyles(storeTheme);
const handleFn = (axis: ResizeHandleAxis, ref: any) => {
return <span className={cx(styles[`react-resizable-handle`],styles[`react-resizable-handle-${axis}`])} ref={ref} />;
};

return (
<ReactResizableBox height={height} width={width} className={cx(styles['react-resizable'], className)}
minConstraints={[minWidth, minHeight]}
maxConstraints={[maxWidth, maxHeight]}
axis={axis}
resizeHandles={resizeHandles}
onResize={onResize}
handle={handleFn}>
{children}
</ReactResizableBox>
);
}
Loading

0 comments on commit 661331d

Please sign in to comment.