+>(({ className, ...props }, ref) => (
+ [role=checkbox]]:translate-y-[2px]",
+ className
+ )}
+ {...props}
+ />
+))
+TableCell.displayName = "TableCell"
+
+const TableCaption = React.forwardRef<
+ HTMLTableCaptionElement,
+ React.HTMLAttributes
+>(({ className, ...props }, ref) => (
+
+))
+TableCaption.displayName = "TableCaption"
+
+export {
+ Table,
+ TableHeader,
+ TableBody,
+ TableFooter,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableCaption,
+}
diff --git a/canvas/services/api.ts b/canvas/services/api.ts
index d4d8036..310255f 100644
--- a/canvas/services/api.ts
+++ b/canvas/services/api.ts
@@ -3,7 +3,9 @@ import { retry } from "wretch/middlewares";
const BASE_URL = process.env.NEXT_PUBLIC_BACKEND_BASE_URL;
-export const api = wretch(BASE_URL);
+export const api = wretch(BASE_URL).options({
+ cache: "no-store", // Disables caching
+});
export type TResponse = {
ok?: boolean;
diff --git a/canvas/services/job.ts b/canvas/services/job.ts
index 855c47a..1cc9f8f 100644
--- a/canvas/services/job.ts
+++ b/canvas/services/job.ts
@@ -5,6 +5,11 @@ export type TProjectStepJobOutput = {
uri: string;
};
+export type TProjectStepJobInput = {
+ type: string;
+ value: string;
+};
+
export type TProjectStepJob = {
id: string | number;
step_id: string | number;
@@ -12,6 +17,7 @@ export type TProjectStepJob = {
description: string;
type: string;
outputs: Record;
+ inputs: Record;
};
export type TGetStepJobsOptions = {
@@ -77,3 +83,24 @@ export async function executeJob(
};
}
}
+
+export type TUpdateStepJobsOptions = {
+ job: TProjectStepJob;
+};
+
+export async function updateJob(options: TUpdateStepJobsOptions) {
+ const { job } = options;
+
+ try {
+ await api.put({ ...job }, "/job").json();
+
+ return {
+ ok: true,
+ };
+ } catch (error) {
+ console.error(error);
+ return {
+ error,
+ };
+ }
+}
diff --git a/canvas/services/run.ts b/canvas/services/run.ts
index de6a48c..241b224 100644
--- a/canvas/services/run.ts
+++ b/canvas/services/run.ts
@@ -1,4 +1,5 @@
import { api, TResponse } from "./api";
+import { TProjectStepJobInput, TProjectStepJobOutput } from "./job";
export type TRunStatus = "pending" | "running" | "success" | "failed" | "init";
@@ -7,6 +8,8 @@ export type TProjectStepJobRun = {
job_id: string | number;
name: string;
run_status: TRunStatus;
+ outputs: Record;
+ inputs: Record;
};
export type TGetStepJobsRunOptions = {
diff --git a/canvas/services/s3.ts b/canvas/services/s3.ts
index cd5c7cc..439fad7 100644
--- a/canvas/services/s3.ts
+++ b/canvas/services/s3.ts
@@ -1,28 +1,54 @@
-import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3";
+import { getAWSCredentials } from "@/utils/localstorage";
+import {
+ GetObjectCommand,
+ S3Client,
+ PutObjectCommand,
+} from "@aws-sdk/client-s3";
export type TFileType = "png" | "csv" | "tsv" | "xlsx" | "txt";
-const getS3Client = (): S3Client => {
+const getS3Client = ({
+ projectId,
+}: {
+ projectId: string | number;
+}): S3Client => {
+ const cred = getAWSCredentials(projectId);
+
+ console.log("Cred", cred, projectId);
+
+ if (!cred) {
+ throw new Error("No AWS credentials found for this project");
+ }
+
return new S3Client({
- region: "us-east-1",
- signer: { sign: async (req) => req },
+ region: cred.region,
+ credentials: {
+ accessKeyId: cred.accessKeyId,
+ secretAccessKey: cred.secretAccessKey,
+ },
});
};
export type TGetKeyFileOptions = {
toString?: {
- encoding: "utf-8" | "base64";
+ encoding?: "utf-8" | "base64";
};
+ projectId: string | number;
};
-const getFile = async (Key: string, options = {} as TGetKeyFileOptions) => {
+const getFile = async (url: string, options = {} as TGetKeyFileOptions) => {
+ /**
+ * Extract bucket and key from the url
+ */
+ const [Bucket, ...rest] = url.replace("s3://", "").split("/");
const command = new GetObjectCommand({
- Bucket: process.env.NEXT_PUBLIC_BUCKET_NAME,
- Key,
+ Bucket,
+ Key: rest.join("/"),
});
- const client = getS3Client();
- const { toString } = options;
+ const { toString, projectId } = options;
+ const client = getS3Client({ projectId });
+
try {
const response = await client.send(command);
@@ -36,4 +62,34 @@ const getFile = async (Key: string, options = {} as TGetKeyFileOptions) => {
}
};
-export { getS3Client, getFile };
+export type TUpdateFileOptions = {
+ ContentType: string;
+ Body: string | Uint8Array | Buffer | File;
+ projectId: string | number;
+};
+
+const uploadToS3 = async (url: string, options: TUpdateFileOptions) => {
+ /**
+ * Extract bucket and key from the url
+ */
+ const [Bucket, ...rest] = url.replace("s3://", "").split("/");
+
+ const command = new PutObjectCommand({
+ Bucket,
+ Key: rest.join("/"),
+ Body: options.Body,
+ ContentType: options.ContentType,
+ });
+
+ const { projectId } = options;
+
+ const client = getS3Client({ projectId });
+ try {
+ const response = await client.send(command);
+ return response;
+ } catch (err) {
+ console.log(err);
+ }
+};
+
+export { getS3Client, getFile, uploadToS3 };
diff --git a/canvas/utils/download.ts b/canvas/utils/download.ts
new file mode 100644
index 0000000..742501e
--- /dev/null
+++ b/canvas/utils/download.ts
@@ -0,0 +1,29 @@
+export type TDownloadFileOptions = {
+ content: string | Uint8Array;
+ filename: string;
+};
+
+export function downloadFile(options: TDownloadFileOptions) {
+ const { content, filename } = options;
+ let type = "application/";
+
+ if (filename.endsWith(".txt")) {
+ type += "txt";
+ } else if (filename.endsWith(".xlsx")) {
+ type += "xlsx";
+ } else if (filename.endsWith(".csv")) {
+ type += "csv";
+ } else if (filename.endsWith(".tsv")) {
+ type += "tsv";
+ } else if (filename.endsWith(".png")) {
+ type = "image/png";
+ }
+
+ console.log("Type", type);
+
+ const blob = new Blob([content], { type });
+ const link = document.createElement("a");
+ link.href = window.URL.createObjectURL(blob);
+ link.download = filename;
+ link.click();
+}
diff --git a/canvas/utils/localstorage.ts b/canvas/utils/localstorage.ts
new file mode 100644
index 0000000..bb8ba15
--- /dev/null
+++ b/canvas/utils/localstorage.ts
@@ -0,0 +1,85 @@
+/**
+ * To return the value using key from the localStorage.
+ */
+export const getLocalStorageValue = (key: string): unknown => {
+ if (typeof window === "undefined") {
+ return null;
+ }
+
+ if (!localStorage.getItem(key)) {
+ return null;
+ }
+ try {
+ return JSON.parse(localStorage.getItem(key)!);
+ } catch (e) {
+ console.error("Error parsing localStorage value", e);
+ return null;
+ }
+};
+
+/**
+ * To store the value in the localStorage using key.
+ */
+export const setLocalStorageValue = (key: string, value: unknown) => {
+ if (typeof window === "undefined") {
+ return false;
+ }
+
+ try {
+ localStorage.setItem(key, JSON.stringify(value));
+ return true;
+ } catch (e) {
+ console.error("Error setting localStorage value", e);
+ return false;
+ }
+};
+
+export type TAWSCredentials = {
+ accessKeyId: string;
+ secretAccessKey: string;
+ region: string;
+};
+
+export const getAWSCredentials = (
+ projectId: string | number
+): TAWSCredentials | null => {
+ const key = `aws-credentials-${projectId}`;
+ const value = getLocalStorageValue(key);
+
+ if (typeof value !== "string" || !value) {
+ return null;
+ }
+
+ try {
+ const parsedValue = JSON.parse(value) as unknown;
+
+ if (typeof parsedValue !== "object" || !parsedValue) {
+ return null;
+ }
+
+ if (
+ "accessKeyId" in parsedValue &&
+ "secretAccessKey" in parsedValue &&
+ "region" in parsedValue
+ ) {
+ return parsedValue as TAWSCredentials;
+ }
+
+ return null;
+ } catch (e) {
+ console.error("Error parsing localStorage value", e);
+ return null;
+ }
+};
+
+export const setAWSCredentials = (
+ projectId: string | number,
+ value: TAWSCredentials
+) => {
+ const key = `aws-credentials-${projectId}`;
+ try {
+ setLocalStorageValue(key, JSON.stringify(value)) || "";
+ } catch (error) {
+ console.log("Error setting AWS credentials", error);
+ }
+};
|