mirror of
https://github.com/dathere/ckan-devstaller.git
synced 2025-11-09 13:39:49 +00:00
feat(docs): add interactivity to Builder, sync with command, add sonner toast
This commit is contained in:
parent
25bb877fb6
commit
56ae938e6c
12 changed files with 423 additions and 80 deletions
107
docs/components/builder-sections/ckan-extensions.tsx
Normal file
107
docs/components/builder-sections/ckan-extensions.tsx
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
import defaultMdxComponents from "fumadocs-ui/mdx";
|
||||
import { SailboatIcon, TerminalSquareIcon } from "lucide-react";
|
||||
import { Config, selectedCardClasses } from "../builder";
|
||||
import { toast } from "sonner";
|
||||
|
||||
const getExtensionClassName = (config: Config, extensionName: string) => {
|
||||
return config.extensions.includes(extensionName) ? selectedCardClasses : "";
|
||||
};
|
||||
|
||||
const updateExtensions = (
|
||||
config: Config,
|
||||
setConfig: any,
|
||||
extensions: string[] | string,
|
||||
mode?: "add" | "remove",
|
||||
) => {
|
||||
const extensionsArray = Array.isArray(extensions) ? extensions : [extensions];
|
||||
if (mode === "add") {
|
||||
setConfig({
|
||||
...config,
|
||||
extensions: [...new Set([...config.extensions, ...extensionsArray])],
|
||||
});
|
||||
return;
|
||||
}
|
||||
for (const extensionName of extensionsArray) {
|
||||
if (config.extensions.includes(extensionName))
|
||||
setConfig({
|
||||
...config,
|
||||
extensions: config.extensions.filter(
|
||||
(extension) => extension !== extensionName,
|
||||
),
|
||||
});
|
||||
else if (!config.extensions.includes(extensionName))
|
||||
setConfig({
|
||||
...config,
|
||||
extensions: [...config.extensions, extensionName],
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default function CKANExtensionsBuilderSection({
|
||||
config,
|
||||
setConfig,
|
||||
}: {
|
||||
config: Config;
|
||||
setConfig: any;
|
||||
}) {
|
||||
const { Card, Cards } = defaultMdxComponents;
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>CKAN extensions</h3>
|
||||
<Cards>
|
||||
<Card
|
||||
className={getExtensionClassName(config, "ckanext-scheming")}
|
||||
icon={<TerminalSquareIcon />}
|
||||
title="ckanext-scheming"
|
||||
onClick={() => {
|
||||
if (
|
||||
config.extensions.includes("DataPusher+") &&
|
||||
config.extensions.includes("ckanext-scheming")
|
||||
) {
|
||||
toast.error(
|
||||
"You cannot remove the ckanext-scheming extension because the DataPusher+ extension depends on it.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
updateExtensions(config, setConfig, "ckanext-scheming");
|
||||
}}
|
||||
></Card>
|
||||
<Card
|
||||
className={getExtensionClassName(config, "DataStore")}
|
||||
icon={<TerminalSquareIcon />}
|
||||
title="DataStore"
|
||||
onClick={() => {
|
||||
if (
|
||||
config.extensions.includes("DataPusher+") &&
|
||||
config.extensions.includes("DataStore")
|
||||
) {
|
||||
toast.error(
|
||||
"You cannot remove the DataStore extension because the DataPusher+ extension depends on it.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
updateExtensions(config, setConfig, "DataStore");
|
||||
}}
|
||||
></Card>
|
||||
<Card
|
||||
className={getExtensionClassName(config, "DataPusher+")}
|
||||
icon={<TerminalSquareIcon />}
|
||||
title="DataPusher+"
|
||||
onClick={() => {
|
||||
if (config.extensions.includes("DataPusher+")) {
|
||||
updateExtensions(config, setConfig, "DataPusher+");
|
||||
} else {
|
||||
updateExtensions(
|
||||
config,
|
||||
setConfig,
|
||||
["DataPusher+", "ckanext-scheming", "DataStore"],
|
||||
"add",
|
||||
);
|
||||
}
|
||||
}}
|
||||
></Card>
|
||||
</Cards>
|
||||
</>
|
||||
);
|
||||
}
|
||||
39
docs/components/builder-sections/ckan-version.tsx
Normal file
39
docs/components/builder-sections/ckan-version.tsx
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
import defaultMdxComponents from "fumadocs-ui/mdx";
|
||||
import { SailboatIcon } from "lucide-react";
|
||||
import { selectedCardClasses } from "../builder";
|
||||
|
||||
export default function CKANVersionBuilderSection({ config, setConfig }: any) {
|
||||
const { Card, Cards } = defaultMdxComponents;
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>CKAN version</h3>
|
||||
<Cards>
|
||||
<Card
|
||||
icon={<SailboatIcon />}
|
||||
title="2.11.3"
|
||||
className={
|
||||
config.ckanVersion === "2.11.3"
|
||||
? selectedCardClasses
|
||||
: "cursor-pointer"
|
||||
}
|
||||
onClick={() => {
|
||||
setConfig({ ...config, ckanVersion: "2.11.3" });
|
||||
}}
|
||||
></Card>
|
||||
<Card
|
||||
icon={<SailboatIcon />}
|
||||
title="2.10.8"
|
||||
className={
|
||||
config.ckanVersion === "2.10.8"
|
||||
? selectedCardClasses
|
||||
: "cursor-pointer"
|
||||
}
|
||||
onClick={() => {
|
||||
setConfig({ ...config, ckanVersion: "2.10.8" });
|
||||
}}
|
||||
></Card>
|
||||
</Cards>
|
||||
</>
|
||||
);
|
||||
}
|
||||
48
docs/components/builder-sections/features.tsx
Normal file
48
docs/components/builder-sections/features.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import defaultMdxComponents from "fumadocs-ui/mdx";
|
||||
import { SailboatIcon, TerminalSquareIcon } from "lucide-react";
|
||||
import { Config, selectedCardClasses } from "../builder";
|
||||
|
||||
const getFeatureClassName = (config: Config, featureName: string) => {
|
||||
return config.features.includes(featureName) ? selectedCardClasses : "";
|
||||
};
|
||||
|
||||
const updateFeatures = (
|
||||
config: Config,
|
||||
setConfig: any,
|
||||
featureName: string,
|
||||
) => {
|
||||
if (config.features.includes(featureName))
|
||||
setConfig({
|
||||
...config,
|
||||
features: config.features.filter((feature) => feature !== featureName),
|
||||
});
|
||||
else setConfig({ ...config, features: [...config.features, featureName] });
|
||||
};
|
||||
|
||||
export default function FeaturesBuilderSection({
|
||||
config,
|
||||
setConfig,
|
||||
}: {
|
||||
config: Config;
|
||||
setConfig: any;
|
||||
}) {
|
||||
const { Card, Cards } = defaultMdxComponents;
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>Features</h3>
|
||||
<Cards>
|
||||
<Card
|
||||
className={getFeatureClassName(config, "enable-ssh")}
|
||||
icon={<TerminalSquareIcon />}
|
||||
title="Enable SSH"
|
||||
onClick={() => {
|
||||
updateFeatures(config, setConfig, "enable-ssh");
|
||||
}}
|
||||
>
|
||||
Installs the openssh-server package.
|
||||
</Card>
|
||||
</Cards>
|
||||
</>
|
||||
);
|
||||
}
|
||||
63
docs/components/builder-sections/presets.tsx
Normal file
63
docs/components/builder-sections/presets.tsx
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import { Config, selectedCardClasses } from "../builder";
|
||||
import { BarChartBigIcon, SailboatIcon } from "lucide-react";
|
||||
import defaultMdxComponents from "fumadocs-ui/mdx";
|
||||
|
||||
export default function PresetsBuilderSection({
|
||||
config,
|
||||
setConfig,
|
||||
}: {
|
||||
config: Config;
|
||||
setConfig: any;
|
||||
}) {
|
||||
const { Card, Cards } = defaultMdxComponents;
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3>Presets</h3>
|
||||
<Cards className="grid-cols-2">
|
||||
<Card
|
||||
className={
|
||||
config.preset === "ckan-only" &&
|
||||
config.extensions.length === 0 &&
|
||||
config.features.length === 0
|
||||
? selectedCardClasses
|
||||
: "cursor-pointer"
|
||||
}
|
||||
icon={<SailboatIcon />}
|
||||
title="CKAN-only"
|
||||
onClick={() => {
|
||||
setConfig({
|
||||
...config,
|
||||
preset: "ckan-only",
|
||||
extensions: [],
|
||||
features: [],
|
||||
});
|
||||
}}
|
||||
>
|
||||
Installs CKAN with ckan-compose. No CKAN extensions and extra features
|
||||
are installed.
|
||||
</Card>
|
||||
<Card
|
||||
className={
|
||||
config.preset === "dathere-default"
|
||||
? selectedCardClasses
|
||||
: "cursor-pointer"
|
||||
}
|
||||
icon={<BarChartBigIcon />}
|
||||
title="datHere Default"
|
||||
onClick={() => {
|
||||
setConfig({
|
||||
...config,
|
||||
preset: "dathere-default",
|
||||
ckanVersion: "2.11.3",
|
||||
extensions: ["ckanext-scheming", "DataStore", "DataPusher+"],
|
||||
features: ["enable-ssh"],
|
||||
});
|
||||
}}
|
||||
>
|
||||
datHere's default preset featuring the DataPusher+ extension.
|
||||
</Card>
|
||||
</Cards>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -8,23 +8,60 @@ import {
|
|||
SailboatIcon,
|
||||
TerminalSquareIcon,
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import PresetsBuilderSection from "./builder-sections/presets";
|
||||
import CKANVersionBuilderSection from "./builder-sections/ckan-version";
|
||||
import CKANExtensionsBuilderSection from "./builder-sections/ckan-extensions";
|
||||
import FeaturesBuilderSection from "./builder-sections/features";
|
||||
|
||||
type Config = {
|
||||
export type Config = {
|
||||
preset: string | undefined;
|
||||
ckanVersion: string;
|
||||
extensions: string[];
|
||||
features: string[];
|
||||
};
|
||||
|
||||
export const selectedCardClasses =
|
||||
"bg-blue-100 dark:bg-blue-950 border-blue-300 dark:border-blue-900 border-2";
|
||||
|
||||
export default function Builder() {
|
||||
const { Card, Cards } = defaultMdxComponents;
|
||||
const [command, setCommand] = useState("./ckan-devstaller");
|
||||
const [config, setConfig] = useState<Config>({
|
||||
preset: undefined,
|
||||
preset: "ckan-only",
|
||||
ckanVersion: "2.11.3",
|
||||
extensions: [],
|
||||
features: [],
|
||||
});
|
||||
|
||||
// Update command string when user changes configuration
|
||||
useEffect(() => {
|
||||
let presetString = "";
|
||||
if (config.extensions.length === 0 && config.features.length === 0)
|
||||
presetString = ` \\\n--preset ckan-only`;
|
||||
else if (
|
||||
config.ckanVersion === "2.11.3" &&
|
||||
config.extensions.includes("DataPusher+") &&
|
||||
config.extensions.includes("ckanext-scheming") &&
|
||||
config.extensions.includes("DataStore") &&
|
||||
config.features.includes("enable-ssh")
|
||||
)
|
||||
presetString = ` \\\n--preset dathere-default`;
|
||||
const ckanVersionString = `--ckan-version ${config.ckanVersion}`;
|
||||
const extensionsString =
|
||||
config.extensions.length > 0
|
||||
? ` \\\n--extensions ${config.extensions.join(" ")}`
|
||||
: undefined;
|
||||
const featuresString =
|
||||
config.features.length > 0
|
||||
? ` \\\n--features ${config.features.join(" ")}`
|
||||
: undefined;
|
||||
setCommand(
|
||||
`./ckan-devstaller${presetString} \\
|
||||
${ckanVersionString}${extensionsString ? extensionsString : ""}${featuresString ? featuresString : ""}`,
|
||||
);
|
||||
}, [config]);
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="col-span-1 border-r-2 pr-4">
|
||||
|
|
@ -35,72 +72,38 @@ export default function Builder() {
|
|||
</CodeBlock>
|
||||
<h2>Selected configuration</h2>
|
||||
<div>
|
||||
<strong>CKAN version</strong>: 2.11.3
|
||||
<strong>CKAN version</strong>: {config.ckanVersion}
|
||||
<br />
|
||||
<br />
|
||||
<strong>Extensions:</strong>
|
||||
<ul>
|
||||
<li>DataStore</li>
|
||||
<li>ckanext-scheming</li>
|
||||
<li>DataPusher+</li>
|
||||
</ul>
|
||||
<strong>Extra features:</strong>
|
||||
<ul>
|
||||
<li>Enable SSH</li>
|
||||
</ul>
|
||||
{config.extensions.length > 0 && (
|
||||
<>
|
||||
<strong>Extensions:</strong>
|
||||
<ul>
|
||||
{config.extensions.map((extension) => (
|
||||
<li key={extension}>{extension}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{config.features.length > 0 && (
|
||||
<>
|
||||
<strong>Features:</strong>
|
||||
<ul>
|
||||
{config.features.map((feature) => (
|
||||
<li key={feature}>{feature}</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-2">
|
||||
<h2>Configuration options</h2>
|
||||
<h3>Presets</h3>
|
||||
<Cards className="grid-cols-2">
|
||||
<Card
|
||||
className="bg-blue-100 dark:bg-blue-950 border-blue-300 dark:border-blue-900 border-2"
|
||||
icon={<SailboatIcon />}
|
||||
title="CKAN-only"
|
||||
>
|
||||
Installs CKAN with ckan-compose.
|
||||
</Card>
|
||||
<Card icon={<BlocksIcon />} title="CKAN and the DataStore extension">
|
||||
Installs CKAN and the DataStore extension.
|
||||
</Card>
|
||||
<Card icon={<BarChartBigIcon />} title="datHere Default">
|
||||
Installs CKAN, the DataStore extension, the ckanext-scheming
|
||||
extension, and the DataPusher+ extension.
|
||||
</Card>
|
||||
</Cards>
|
||||
<h3>CKAN version</h3>
|
||||
<Cards>
|
||||
<Card icon={<SailboatIcon />} title="2.11.3"></Card>
|
||||
<Card icon={<SailboatIcon />} title="2.10.8"></Card>
|
||||
<Card
|
||||
icon={<SailboatIcon />}
|
||||
title="Install a different version"
|
||||
></Card>
|
||||
<Card
|
||||
icon={<SailboatIcon />}
|
||||
title="Clone from remote Git repository"
|
||||
></Card>
|
||||
</Cards>
|
||||
<h3>CKAN extensions</h3>
|
||||
<Cards>
|
||||
<Card icon={<TerminalSquareIcon />} title="ckanext-scheming"></Card>
|
||||
<Card icon={<TerminalSquareIcon />} title="ckanext-gztr"></Card>
|
||||
<Card icon={<TerminalSquareIcon />} title="DataStore"></Card>
|
||||
<Card icon={<TerminalSquareIcon />} title="DataPusher+"></Card>
|
||||
<Card icon={<TerminalSquareIcon />} title="ckanext-spatial"></Card>
|
||||
<Card icon={<TerminalSquareIcon />} title="Custom extension"></Card>
|
||||
</Cards>
|
||||
<h3>Extra features</h3>
|
||||
<Cards>
|
||||
<Card icon={<TerminalSquareIcon />} title="Enable SSH">
|
||||
Installs openssh-server and net-tools.
|
||||
</Card>
|
||||
<Card icon={<TerminalSquareIcon />} title="Run a Bash script">
|
||||
Run a Bash script before or after any step during the installation.
|
||||
</Card>
|
||||
</Cards>
|
||||
<PresetsBuilderSection config={config} setConfig={setConfig} />
|
||||
<CKANVersionBuilderSection config={config} setConfig={setConfig} />
|
||||
<CKANExtensionsBuilderSection config={config} setConfig={setConfig} />
|
||||
<FeaturesBuilderSection config={config} setConfig={setConfig} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
40
docs/components/ui/sonner.tsx
Normal file
40
docs/components/ui/sonner.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
"use client";
|
||||
|
||||
import {
|
||||
CircleCheckIcon,
|
||||
InfoIcon,
|
||||
Loader2Icon,
|
||||
OctagonXIcon,
|
||||
TriangleAlertIcon,
|
||||
} from "lucide-react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Toaster as Sonner, ToasterProps } from "sonner";
|
||||
|
||||
const Toaster = ({ ...props }: ToasterProps) => {
|
||||
const { theme = "system" } = useTheme();
|
||||
|
||||
return (
|
||||
<Sonner
|
||||
theme={theme as ToasterProps["theme"]}
|
||||
className="toaster group"
|
||||
icons={{
|
||||
success: <CircleCheckIcon className="size-4" />,
|
||||
info: <InfoIcon className="size-4" />,
|
||||
warning: <TriangleAlertIcon className="size-4" />,
|
||||
error: <OctagonXIcon className="size-4" />,
|
||||
loading: <Loader2Icon className="size-4 animate-spin" />,
|
||||
}}
|
||||
style={
|
||||
{
|
||||
"--normal-bg": "var(--popover)",
|
||||
"--normal-text": "var(--popover-foreground)",
|
||||
"--normal-border": "var(--border)",
|
||||
"--border-radius": "var(--radius)",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export { Toaster };
|
||||
Loading…
Add table
Add a link
Reference in a new issue