Skip to content

Commit

Permalink
CSV Example WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorreece committed Aug 21, 2024
1 parent bd0008f commit 3e51066
Show file tree
Hide file tree
Showing 9 changed files with 434 additions and 0 deletions.
15 changes: 15 additions & 0 deletions example-embedded-app/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions example-embedded-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
"context-api": "0.0.2",
"date-fns": "2.30.0",
"jsonwebtoken": "^9.0.0",
"ka-table": "^11.0.3",
"next": "12.3.4",
"nprogress": "0.2.0",
"papaparse": "^5.4.1",
"react": "17.0.2",
"react-apexcharts": "1.4.0",
"react-custom-scrollbars-2": "4.5.0",
Expand Down
30 changes: 30 additions & 0 deletions example-embedded-app/pages/csv-example/CsvDataTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Table } from "ka-table";
import { DataType, EditingMode, SortingMode } from "ka-table/enums";
import "ka-table/style.css";

function CsvDataTable({ data, table }) {
if (data === null || data.length === 0) {
return null;
}

const columns = Object.keys(data[0]).map((key) => ({
key,
title: key,
dataType: DataType.String,
}));

const rows = data.map((row, index) => ({ ...row, id: index }));

return (
<Table
columns={columns}
data={rows}
table={table}
editingMode={EditingMode.Cell}
rowKeyField={"id"}
sortingMode={SortingMode.Single}
/>
);
}

export default CsvDataTable;
39 changes: 39 additions & 0 deletions example-embedded-app/pages/csv-example/PrismaticAvatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { CableTwoTone } from "@mui/icons-material";
import { Avatar } from "@mui/material";
import config from "prismatic/config";
import React from "react";

function PrismaticAvatar({ avatarUrl, token }) {
const [src, setSrc] = React.useState("");

React.useEffect(() => {
let mounted = true;
if (avatarUrl) {
fetch(`${config.prismaticUrl}${avatarUrl}`, {
headers: { Authorization: `Bearer ${token}` },
}).then((response) => {
response.json().then((data) => {
if (mounted) {
setSrc(data.url);
}
});
});
}

return () => {
mounted = false;
};
}, []);

if (!avatarUrl) {
return (
<Avatar>
<CableTwoTone />
</Avatar>
);
}

return src ? <Avatar variant="rounded" src={src} /> : null;
}

export default PrismaticAvatar;
99 changes: 99 additions & 0 deletions example-embedded-app/pages/csv-example/UploadButtons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
Alert,
Box,
Button,
Container,
LinearProgress,
TextField,
} from "@mui/material";
import Papa from "papaparse";
import React, { Dispatch, SetStateAction } from "react";
import { Instance } from "./getInstances";

interface UploadCsvParams {
fileName: string;
uploadUrl: string;
data: unknown[];
setUploadState: Dispatch<SetStateAction<UploadState>>;
}

function uploadCsv({
fileName,
uploadUrl,
data,
setUploadState,
}: UploadCsvParams) {
setUploadState("uploading");
const csvData = Papa.unparse(data.map(({ id, ...rest }) => rest));
const formData = new FormData();
formData.append("file", csvData);
formData.append("fileName", fileName);
fetch(uploadUrl, { method: "post", body: formData })
.then(() => {
setUploadState("success");
setTimeout(() => setUploadState("idle"), 4000);
})
.catch(() => {
setUploadState("failed");
});
}

type UploadState = "idle" | "uploading" | "success" | "failed";

function ProgressIndicator({ state }: { state: UploadState }) {
switch (state) {
case "idle":
return null;
case "uploading":
return (
<Box>
<LinearProgress />
</Box>
);
case "success":
return <Alert severity="success">Upload successful</Alert>;
case "failed":
return <Alert severity="error">Upload failed</Alert>;
}
}

function UploadButtons({
data,
instances,
}: {
data: any;
instances: Instance[];
}) {
const [fileName, setFileName] = React.useState("");
const [uploadState, setUploadState] = React.useState<UploadState>("idle");

return (
<Container>
<hr />
<TextField
onChange={({ target }) => {
setFileName(target.value);
}}
label="File Name"
/>
{instances.map((instance) => (
<Button
key={instance.integration.name}
onClick={() => {
uploadCsv({
fileName,
uploadUrl: instance.webhookUrls["upload"],
data,
setUploadState,
});
}}
>
Upload to {instance.integration.name}
</Button>
))}
<ProgressIndicator state={uploadState} />
</Container>
);
}

export default UploadButtons;
3 changes: 3 additions & 0 deletions example-embedded-app/pages/csv-example/csv-example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## CSV Load and Upload Example

This example demonstrates interactivity between an application and a set of Prismatic instances that a customer has deployed.
78 changes: 78 additions & 0 deletions example-embedded-app/pages/csv-example/getInstances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import prismatic from "@prismatic-io/embedded";

export interface Instance {
id: string;
enabled: boolean;
flowConfigs: FlowConfigs;
integration: Integration;
webhookUrls: Record<string, string>;
}

export interface FlowConfigs {
nodes: FlowConfigsNode[];
}

export interface FlowConfigsNode {
flow: Flow;
webhookUrl: string;
}

export interface Flow {
name: string;
}

export interface Integration {
id: string;
name: string;
avatarUrl: null | string;
category: Category;
}

export enum Category {
CSVStores = "CSV Stores",
Communication = "Communication",
Empty = "",
}
const query = `query getInstances {
instances {
nodes {
id
enabled
flowConfigs {
nodes {
flow {
name
}
webhookUrl
}
}
integration {
id
name
avatarUrl
category
}
}
}
}
`;

const getInstances = (): Promise<Instance[]> => {
return prismatic.graphqlRequest({ query }).then((response) => {
const csvInstances = (response.data.instances.nodes as Instance[]).filter(
(instance) => instance.integration.category === "CSV Stores",
);
// Make webhook URLs more accessible
for (const instance of csvInstances) {
instance.webhookUrls = Object.fromEntries(
instance.flowConfigs.nodes.map((flowConfig) => [
flowConfig.flow.name,
flowConfig.webhookUrl,
]),
);
}
return csvInstances;
});
};

export default getInstances;
Loading

0 comments on commit 3e51066

Please sign in to comment.