Skip to content

Commit

Permalink
docs: improve config generator (txpipe#696)
Browse files Browse the repository at this point in the history
  • Loading branch information
caike authored Nov 25, 2023
1 parent ed54b32 commit cdaa596
Show file tree
Hide file tree
Showing 2 changed files with 179 additions and 72 deletions.
16 changes: 16 additions & 0 deletions docs/components/clipboardIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const clipBoardIcon = () => {
return (
<>
<svg className="h-8 w-8 stroke-slate-500 hover:stroke-slate-900 transition group-hover:rotate-[-4deg] group-hover:stroke-slate-600"
fill="none" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"
strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M12.9975 10.7499L11.7475 10.7499C10.6429 10.7499 9.74747 11.6453 9.74747 12.7499L9.74747 21.2499C9.74747 22.3544 10.6429 23.2499 11.7475 23.2499L20.2475 23.2499C21.352 23.2499 22.2475 22.3544 22.2475 21.2499L22.2475 12.7499C22.2475 11.6453 21.352 10.7499 20.2475 10.7499L18.9975 10.7499" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
<path d="M17.9975 12.2499L13.9975 12.2499C13.4452 12.2499 12.9975 11.8022 12.9975 11.2499L12.9975 9.74988C12.9975 9.19759 13.4452 8.74988 13.9975 8.74988L17.9975 8.74988C18.5498 8.74988 18.9975 9.19759 18.9975 9.74988L18.9975 11.2499C18.9975 11.8022 18.5498 12.2499 17.9975 12.2499Z" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
<path d="M13.7475 16.2499L18.2475 16.2499" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
<path d="M13.7475 19.2499L18.2475 19.2499" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path><g className="opacity-0">
<path d="M15.9975 5.99988L15.9975 3.99988" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
<path d="M19.9975 5.99988L20.9975 4.99988" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path>
<path d="M11.9975 5.99988L10.9975 4.99988" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"></path></g></svg>
</>);

}
235 changes: 163 additions & 72 deletions docs/components/configuration.jsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,151 @@
import { useState } from "react";
import { useState, useReducer } from "react";
import json2toml from "json2toml";
import { clipBoardIcon } from "./clipboardIcon";

function reducer(state, action) {
switch (action.name) {

case 'add_source': {
const currentStages = state.currentStages;
currentStages.source = action.source;
currentStages.intersect = action.intersect;

const _tomlContent = json2toml(currentStages, { newlineAfterSection: true });
const tomlContent = (_tomlContent || "").trim();

return {
...state,
currentStages,
tomlContent,
openedModal: false,
};
}

case 'add_filter': {
const currentStages = state.currentStages;

const hasFilterIndex = currentStages.filters?.findIndex(
(s) => s.type == action.stage.type
);

if (hasFilterIndex != undefined && hasFilterIndex != -1) {
currentStages.filters[hasFilterIndex] = action.stage;
} else {
currentStages.filters = currentStages.filters?.concat(action.stage) || [action.stage];
}

const _tomlContent = json2toml(currentStages, { newlineAfterSection: true });
const tomlContent = (_tomlContent || "").trim();

return {
...state,
currentStages,
tomlContent,
openedModal: false
};
}

case 'add_sink': {
const currentStages = state.currentStages;
currentStages.sink = action.stage;

const _tomlContent = json2toml(currentStages, { newlineAfterSection: true });
const tomlContent = (_tomlContent || "").trim();

return {
...state,
currentStages,
openedModal: false,
tomlContent
};
}

case 'open_modal': {
return {
...state,
openedModal: true,
typeModal: action.type,
optionModal: undefined
};
};

case 'close_modal': {
return {
...state,
openedModal: false
};
};

case 'set_option_modal': {
return {
...state,
optionModal: action.value
};
};

case 'reset': {
return {
...state,
currentStages: {},
tomlContent: ""
};
};
}
throw Error('Unknown action: ' + action.name);
}

export function Configuration() {
const [openedModal, setOpenedModal] = useState(false);
const [typeModal, setTypeModal] = useState();
const [optionModal, setoOptionModal] = useState(undefined);

const [currentStages, setCurrentStages] = useState({});
const [state, dispatch] = useReducer(reducer,
{
openedModal: false,
typeModal: null,
optionModal: undefined,
currentStages: {},
tomlContent: ""
}
);

const addSourceStage = ({ source, intersect }) => {
currentStages.source = source;
currentStages.intersect = intersect;
setCurrentStages(currentStages);
setOpenedModal(false);
dispatch({ name: 'add_source', source, intersect });
};

const addFilterStage = (stage) => {
const hasFilterIndex = currentStages.filters?.findIndex(
(s) => s.type == stage.type
);

if (hasFilterIndex != undefined && hasFilterIndex != -1) {
currentStages.filters[hasFilterIndex] = stage;
} else {
currentStages.filters = currentStages.filters?.concat(stage) || [stage];
}

setCurrentStages(currentStages);
setOpenedModal(false);
dispatch({ name: 'add_filter', stage });
};

const addSinkStage = (stage) => {
currentStages.sink = stage;
setCurrentStages(currentStages);
setOpenedModal(false);
dispatch({ name: 'add_sink', stage });
};

function openModal(type) {
setOpenedModal(true);
setTypeModal(type);
setoOptionModal(undefined);
dispatch({ name: 'open_modal', type });
}

function exportConfig() {
if (!currentStages.source) {
alert("Add a source");
return;
}
function closeModal() {
dispatch({ name: 'close_modal' });
}

if (!currentStages.sink) {
alert("Add a sink");
return;
}
function setOptionModal(value) {
dispatch({ name: 'set_option_modal', value });
}

var element = document.createElement("a");
element.setAttribute(
"href",
"data:text/plain;charset=utf-8," +
encodeURIComponent(
json2toml(currentStages, { newlineAfterSection: true })
)
);
element.setAttribute("download", "daemon.toml");
function reset() {
dispatch({ name: 'reset' });
}

function copyToClipboard(button) {

element.style.display = "none";
document.body.appendChild(element);
const smallCopy = document.getElementById('small-copy');

element.click();
navigator.clipboard.writeText(state.tomlContent).then(res => {
const originalSmallCopy = smallCopy.innerHTML;
smallCopy.innerHTML = "Copied!";

document.body.removeChild(element);
setTimeout(() => {
smallCopy.innerHTML = originalSmallCopy;
}, 1000);
});
}

const TYPES = {
Expand Down Expand Up @@ -109,18 +186,18 @@ export function Configuration() {
return (
<div>
<div className="absolute">
{openedModal ? (
{state.openedModal ? (
<>
<div className="flex items-center overflow-y-auto fixed inset-0 z-50">
<div className="my-6 mx-auto max-w-3xl w-full">
<div className="rounded-lg shadow-lg bg-white dark:bg-gray-700">
<div className="flex justify-between p-5">
<h3 className="text-3xl font-semibold capitalize">
{typeModal}
{state.typeModal}
</h3>
<button
className="p-1 float-right text-3xl leading-none"
onClick={() => setOpenedModal(false)}
onClick={closeModal}
>
<span className="text-gray dark:text-gray-200">×</span>
</button>
Expand All @@ -131,17 +208,17 @@ export function Configuration() {
name="stage"
id="stage"
className="w-full py-2 px-4 rounded mb-2"
onChange={(e) => setoOptionModal(e.target.value)}
value={optionModal}
onChange={(e) => setOptionModal(e.target.value)}
value={state.optionModal}
>
<option>-</option>
{Object.keys(stages[typeModal]).map((k) => (
{Object.keys(stages[state.typeModal]).map((k) => (
<option value={k} key={k}>
{k}
</option>
))}
</select>
{optionModal ? stages[typeModal][optionModal] : null}
{state.optionModal ? stages[state.typeModal][state.optionModal] : null}
</div>
</div>
</div>
Expand All @@ -161,18 +238,12 @@ export function Configuration() {

<div className="py-5 flex justify-end">
<button
className="px-4 py-2 rounded font-bold me-2 text-red-500"
onClick={() => setCurrentStages({})}
className="px-4 py-2 rounded font-bold me-2 text-red-500 bg-red-100 hover:bg-red-200"
onClick={reset}
>
reset
</button>

<button
className="border border-gray-500 text-gray-500 dark:text-gray-200 hover:bg-gray-500 hover:text-white hover:dark:text-gray-200 px-4 py-2 rounded font-bold "
onClick={exportConfig}
>
export config
</button>
</div>

<div className="grid sm:grid-cols-3 grid-cols-1 gap-3">
Expand All @@ -184,11 +255,11 @@ export function Configuration() {
add source
</button>

{currentStages.source ? (
{state.currentStages.source ? (
<StageCard
value={{
...currentStages.source,
intersect: currentStages.intersect,
...state.currentStages.source,
intersect: state.currentStages.intersect,
}}
/>
) : null}
Expand All @@ -200,7 +271,7 @@ export function Configuration() {
>
add filter
</button>
{currentStages[TYPES.FILTERS]?.map((value, index) => (
{state.currentStages[TYPES.FILTERS]?.map((value, index) => (
<div key={index}>
<StageCard value={value} />
</div>
Expand All @@ -215,13 +286,33 @@ export function Configuration() {
add sink
</button>

{currentStages.sink ? (
<StageCard value={currentStages.sink} />
{state.currentStages.sink ? (
<StageCard value={state.currentStages.sink} />
) : null}
</div>
</div>
</div>
</div>

{state.tomlContent && state.tomlContent.length > 0 && (
<div className="p-2">
<div className="flex justify-between">
<small className="mt-4">config.toml</small>
<span className="flex">
<small className="mt-2" id="small-copy">Copy to clipboard</small>
<button
className="group relative"
onClick={(e) => copyToClipboard(e.target)}>
{clipBoardIcon()}
</button>
</span>
</div>
<div className="py-5 mt-2 bg-slate-100 rounded-md dark:bg-gray-800 dark:text-gray-400">
<pre>{state.tomlContent}</pre>
</div>
</div>
)
}
</div >
);
}

Expand Down Expand Up @@ -1841,4 +1932,4 @@ function StageCard({ value }) {
))}
</div>
);
}
}

0 comments on commit cdaa596

Please sign in to comment.