From 6e5088e79cb8f220ec07f4fe0f7af0baf8f80301 Mon Sep 17 00:00:00 2001 From: Karume-lab <danielkarume@outlook.com> Date: Thu, 6 Jun 2024 12:39:07 +0300 Subject: [PATCH 1/2] feat: :sparkles: embedding superset succesfully embedded superset dashboard using embed id --- package-lock.json | 120 +++- package.json | 2 + src/app/dashboard/innovation/[id]/page.tsx | 678 ++++++++++++--------- superset-embed | 1 + 4 files changed, 504 insertions(+), 297 deletions(-) create mode 160000 superset-embed diff --git a/package-lock.json b/package-lock.json index 4fb9ba9..74ee974 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,9 @@ "@radix-ui/react-toast": "^1.1.5", "@radix-ui/themes": "^3.0.3", "@reduxjs/toolkit": "^2.2.3", + "@superset-ui/embedded-sdk": "^0.1.0-alpha.11", "async-mutex": "^0.5.0", + "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.377.0", @@ -7371,6 +7373,22 @@ "url": "https://opencollective.com/storybook" } }, + "node_modules/@superset-ui/embedded-sdk": { + "version": "0.1.0-alpha.11", + "resolved": "https://registry.npmjs.org/@superset-ui/embedded-sdk/-/embedded-sdk-0.1.0-alpha.11.tgz", + "integrity": "sha512-TYD7eLyk5csN5/ms723Oz6oE/jtk5tqp7smub+K/GSPZWy1aArLbWcEp0ARDdqLzRkRpc3gxEwCWDHs3IERAPg==", + "license": "Apache-2.0", + "dependencies": { + "@superset-ui/switchboard": "^0.18.26-0", + "jwt-decode": "^3.1.2" + } + }, + "node_modules/@superset-ui/switchboard": { + "version": "0.18.26-2", + "resolved": "https://registry.npmjs.org/@superset-ui/switchboard/-/switchboard-0.18.26-2.tgz", + "integrity": "sha512-yIuEv8QGS+j+SS3P3TGQ0wp9WGKGHJrI39kjh74N1HFZlHhfZEKZ28XdZIjOEXlqCr7pvrF0XPEzLHnGSsbtCg==", + "license": "Apache-2.0" + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -9397,8 +9415,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/available-typed-arrays": { "version": "1.0.7", @@ -9424,6 +9441,17 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -10840,7 +10868,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -11615,7 +11642,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -13517,6 +13543,26 @@ "node": ">=0.4.0" } }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -13683,7 +13729,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -17527,6 +17572,12 @@ "node": ">=4.0" } }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", + "license": "MIT" + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -17978,7 +18029,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -17987,7 +18037,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -19674,6 +19723,12 @@ "node": ">= 0.10" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", @@ -28428,6 +28483,20 @@ "file-system-cache": "2.3.0" } }, + "@superset-ui/embedded-sdk": { + "version": "0.1.0-alpha.11", + "resolved": "https://registry.npmjs.org/@superset-ui/embedded-sdk/-/embedded-sdk-0.1.0-alpha.11.tgz", + "integrity": "sha512-TYD7eLyk5csN5/ms723Oz6oE/jtk5tqp7smub+K/GSPZWy1aArLbWcEp0ARDdqLzRkRpc3gxEwCWDHs3IERAPg==", + "requires": { + "@superset-ui/switchboard": "^0.18.26-0", + "jwt-decode": "^3.1.2" + } + }, + "@superset-ui/switchboard": { + "version": "0.18.26-2", + "resolved": "https://registry.npmjs.org/@superset-ui/switchboard/-/switchboard-0.18.26-2.tgz", + "integrity": "sha512-yIuEv8QGS+j+SS3P3TGQ0wp9WGKGHJrI39kjh74N1HFZlHhfZEKZ28XdZIjOEXlqCr7pvrF0XPEzLHnGSsbtCg==" + }, "@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -30062,8 +30131,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "available-typed-arrays": { "version": "1.0.7", @@ -30080,6 +30148,16 @@ "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", "dev": true }, + "axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -31136,7 +31214,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -31731,8 +31808,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" }, "depd": { "version": "2.0.0", @@ -33244,6 +33320,11 @@ "integrity": "sha512-s04193L4JE+ntEcQXbD6jxRRlyj9QXcgEl2W6xSjH4l9x4b0eHoCHfbYHjqf9LdZFUiM5LhgpiqsvLj/AyOyYQ==", "dev": true }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, "for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -33364,7 +33445,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -36101,6 +36181,11 @@ "object.values": "^1.1.6" } }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -36452,14 +36537,12 @@ "mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "requires": { "mime-db": "1.52.0" } @@ -37623,6 +37706,11 @@ "ipaddr.js": "1.9.1" } }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", diff --git a/package.json b/package.json index ea6c1ea..5670e09 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "@radix-ui/react-toast": "^1.1.5", "@radix-ui/themes": "^3.0.3", "@reduxjs/toolkit": "^2.2.3", + "@superset-ui/embedded-sdk": "^0.1.0-alpha.11", "async-mutex": "^0.5.0", + "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "lucide-react": "^0.377.0", diff --git a/src/app/dashboard/innovation/[id]/page.tsx b/src/app/dashboard/innovation/[id]/page.tsx index 56d4078..9524909 100644 --- a/src/app/dashboard/innovation/[id]/page.tsx +++ b/src/app/dashboard/innovation/[id]/page.tsx @@ -2,63 +2,65 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuTrigger, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { - Form, - FormField, - FormItem, - FormLabel, - FormControl, - FormMessage, + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, } from "@/components/ui/form"; import { Separator } from "@/components/ui/separator"; import { Textarea } from "@/components/ui/textarea"; import { useToast } from "@/components/ui/use-toast"; import { zodResolver } from "@hookform/resolvers/zod"; import { - Bookmark, - EllipsisVertical, - Heart, - MessageCircle, - Share2, - SquarePen, - Trash2, + Bookmark, + EllipsisVertical, + Heart, + MessageCircle, + Share2, + SquarePen, + Trash2, } from "lucide-react"; import Link from "next/link"; -import React, { useState } from "react"; +import React, { useEffect, useRef, useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import Image from "next/image"; import { - useInnovationsFetchOneQuery, - useInnovationsCommentsCreateMutation, - useInnovationsCommentsListQuery, - useInnovationsCommentsDeleteMutation, - useInnovationsCommentsUpdatePatchMutation, - useInnovationsCommentsUpdatePutMutation, - useInnovationsCommentsReadQuery, + useInnovationsFetchOneQuery, + useInnovationsCommentsCreateMutation, + useInnovationsCommentsListQuery, + useInnovationsCommentsDeleteMutation, + useInnovationsCommentsUpdatePatchMutation, + useInnovationsCommentsUpdatePutMutation, + useInnovationsCommentsReadQuery, } from "@/redux/features/innovations/innovationsApiSlice"; import { get_fallback_name } from "@/lib/utils"; import { - useBookmarkInnovation, - useLikeInnovation, - useUnbookmarkInnovation, - useUnlikeInnovation, + useBookmarkInnovation, + useLikeInnovation, + useUnbookmarkInnovation, + useUnlikeInnovation, } from "@/lib/hooks"; import { PaginationDemo } from "@/components/Pagination"; +import { embedDashboard } from "@superset-ui/embedded-sdk"; +import axios from 'axios'; type InnovationDetailPageProps = { - params: { - id: string; - }; + params: { + id: string; + }; }; const CommentSchema = z.object({ - message: z.string().min(2).max(255), + message: z.string().min(2).max(255), }); type TComment = z.infer<typeof CommentSchema>; @@ -66,269 +68,383 @@ type TComment = z.infer<typeof CommentSchema>; const commentsPerPage = 5; const InnovationDetailPage = ({ params }: InnovationDetailPageProps) => { - const { id } = params; - const handleLike = useLikeInnovation(id); - const handleUnlike = useUnlikeInnovation(id); - const handleBookmark = useBookmarkInnovation(id); - const handleUnbookmark = useUnbookmarkInnovation(id); + const { id } = params; + const handleLike = useLikeInnovation(id); + const handleUnlike = useUnlikeInnovation(id); + const handleBookmark = useBookmarkInnovation(id); + const handleUnbookmark = useUnbookmarkInnovation(id); - const form = useForm<TComment>({ - resolver: zodResolver(CommentSchema), - }); + const form = useForm<TComment>({ + resolver: zodResolver(CommentSchema), + }); - const [currentPage, setCurrentPage] = useState(1); - // Fetch innovation data - const { - data: innovation, - isLoading: isGettingInnovation, - error: errorGettingInnovation, - } = useInnovationsFetchOneQuery(id); - const [createComment, { isLoading: isCreatingComment }] = - useInnovationsCommentsCreateMutation(); - const { - data: commentData, - isLoading: isGettingComment, - error: errorGettingComments, - } = useInnovationsCommentsListQuery({ id: id, page: currentPage }); - console.log(commentData); - // extracting comments from the request - const { - results: comments, - next: nextCommentPage, - previous: previousCommentPage, - count: totalComments, - } = commentData || {}; + const [currentPage, setCurrentPage] = useState(1); + // Fetch innovation data + const { + data: innovation, + isLoading: isGettingInnovation, + error: errorGettingInnovation, + } = useInnovationsFetchOneQuery(id); + const [createComment, { isLoading: isCreatingComment }] = + useInnovationsCommentsCreateMutation(); + const { + data: commentData, + isLoading: isGettingComment, + error: errorGettingComments, + } = useInnovationsCommentsListQuery({ id: id, page: currentPage }); + console.log(commentData); + // extracting comments from the request + const { + results: comments, + next: nextCommentPage, + previous: previousCommentPage, + count: totalComments, + } = commentData || {}; - // * handling pagination - const totalPages = - totalComments && Math.ceil(totalComments / commentsPerPage); - const handlePrevious = () => { - if (currentPage > 1) { - setCurrentPage(currentPage - 1); - } - }; + // * handling pagination + const totalPages = + totalComments && Math.ceil(totalComments / commentsPerPage); + const handlePrevious = () => { + if (currentPage > 1) { + setCurrentPage(currentPage - 1); + } + }; - const handleNext = () => { - if (totalPages && currentPage < totalPages) { - setCurrentPage(currentPage + 1); - } - }; - //initialize toast - const { toast } = useToast(); - //Function that handles submision of validated data - const onSubmit = async (data: TComment) => { - // useInnovationsCommentsDeleteMutation - // useInnovationsCommentsUpdatePatchMutation - // useInnovationsCommentsUpdatePutMutation - // useInnovationsCommentsReadQuery + const handleNext = () => { + if (totalPages && currentPage < totalPages) { + setCurrentPage(currentPage + 1); + } + }; + //initialize toast + const { toast } = useToast(); + //Function that handles submision of validated data + const onSubmit = async (data: TComment) => { + // useInnovationsCommentsDeleteMutation + // useInnovationsCommentsUpdatePatchMutation + // useInnovationsCommentsUpdatePutMutation + // useInnovationsCommentsReadQuery - // Submit the data to your API or perform any other action - createComment({ id, ...data }) - .unwrap() - .then((response) => { - // toast created successfully - toast({ - title: "Comments submitted successfully", - }); - console.log("Response: ", response); - form.reset({ message: "" }); - }) - .catch((error) => { - console.log(error); - }); - }; + // Submit the data to your API or perform any other action + createComment({ id, ...data }) + .unwrap() + .then((response) => { + // toast created successfully + toast({ + title: "Comments submitted successfully", + }); + console.log("Response: ", response); + form.reset({ message: "" }); + }) + .catch((error) => { + console.log(error); + }); + }; - return isGettingInnovation || isGettingComment ? ( - <div>Loading...</div> - ) : errorGettingInnovation || errorGettingComments ? ( - <div>Something went wrong</div> - ) : ( - <main> - <section className="flex flex-col"> - <div className="flex justify-between items-center p-4"> - <h2 className="font-semibold text-3xl">{innovation?.title}</h2> - <DropdownMenu> - <DropdownMenuTrigger asChild> - <div className="hover:bg-accent rounded-full p-1"> - <EllipsisVertical /> - </div> - </DropdownMenuTrigger> - <DropdownMenuContent className="w-56"> - <DropdownMenuItem> - <SquarePen className="mr-2 h-4 w-4" /> - {/* TODO: URL generator */} - <Link href={`/dashboard/innovation/edit/${id}`}> - <span>Edit</span> - </Link> - </DropdownMenuItem> - <DropdownMenuItem className="hover:bg-destructive active:bg-destructive focus:bg-destructive hover:text-white active:text-white focus:text-white"> - <Trash2 className="mr-2 h-4 w-4" /> - <span>Delete</span> - </DropdownMenuItem> - </DropdownMenuContent> - </DropdownMenu> - </div> - <p className="px-4 ">{innovation?.description}</p> - <div className="flex items-center justify-between mt-5 px-4 "> - <div className="flex items-center gap-3"> - <Avatar className="h-12 w-12"> - <AvatarImage src={innovation?.author.profile_picture} /> - <AvatarFallback className="p-2"> - {get_fallback_name( - innovation?.author.first_name, - innovation?.author.last_name - )} - </AvatarFallback> - </Avatar> - <div> - <p>{`${innovation?.author.first_name} ${innovation?.author.last_name}`}</p> - <p className="text-sm">{innovation?.author.email}</p> - </div> - </div> + const supersetUrl = "http://localhost:8088"; + const supersetApiUrl = supersetUrl + "/api/v1/security"; + const dashboardId = "795981b3-a645-425b-a9ea-fe8970bc30dd"; + let supersetData: { access_token: string, refresh_token: string }; - <div className="flex gap-2 md:gap-4"> - {innovation?.dashboard_link && ( - <Link href={innovation?.dashboard_link || ""}> - <Button className="rounded-full md:px-9"> Visit </Button> - </Link> - )} - {innovation?.dashboard_definitions && ( - <Link download href={innovation.dashboard_definitions}> - <Button className="rounded-full" variant={"outline"}> - Download Datasets - </Button> - </Link> - )} - </div> - </div> - <div className="flex p-4 my-2 justify-between bg-accent"> - <div className="flex gap-3"> - <span - className="flex" - onClick={innovation?.is_liked ? handleUnlike : handleLike} - > - {innovation?.is_liked ? ( - <Heart className="fill-red-500" /> - ) : ( - <Heart className="hover:fill-red-500" /> - )}{" "} - {innovation?.likes_number} - </span> - <span className="flex"> - <MessageCircle /> {innovation?.comments_number}{" "} - </span> - </div> - <span - className="flex" - onClick={ - innovation?.is_bookmarked ? handleUnbookmark : handleBookmark - } - > - {innovation?.is_bookmarked ? ( - <Bookmark className="fill-green-600" /> - ) : ( - <Bookmark /> - )} - </span> - </div> - </section> - <section> - {innovation?.dashboard_image ? ( - <Image - alt="Innovation Image" - width={500} - height={600} - src={innovation?.dashboard_image} - /> - ) : ( - <></> - )} - </section> + const dashboardRef = useRef(null); + async function fetchGuestTokenFromBackend() { + const access_token = await getToken() + // Calling guest token + const guest_token_body = { + resources: [ + { + type: "dashboard", + id: dashboardId, + }, + ], + rls: [], + user: { + username: "guest", + first_name: "Guest", + last_name: "User", + }, + }; - <section className="px-6 pb-4"> - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> - <FormField - control={form.control} - name="message" - render={({ field }) => ( - <FormItem> - <FormLabel>Comment</FormLabel> - <FormControl> - <Textarea placeholder="Type comment here..." {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - <Button - className="rounded-full" - type="submit" - size={"lg"} - disabled={isCreatingComment} - > - Submit - </Button> - </form> - </Form> - </section> - {/* Comments container */} - <section className="p-7 space-y-4"> - {comments?.map((comment, index) => ( - <div className="border p-3 rounded-lg shadow-md" key={index}> - <div className="flex items-center justify-between"> - <div className="flex items-center gap-3"> - <Avatar className="h-12 w-12"> - <AvatarImage src={comment.author.profile_picture} /> - <AvatarFallback className="p-2"> - {get_fallback_name( - innovation?.author.first_name, - innovation?.author.last_name - )} - </AvatarFallback> - </Avatar> - <div> - <p> - {comment.author.first_name} {comment.author.last_name} - </p> - <p className="text-sm">{comment.author.email}</p> - </div> - </div> - <DropdownMenu> - <DropdownMenuTrigger asChild> - <div className="hover:bg-accent rounded-full p-1"> - <EllipsisVertical /> - </div> - </DropdownMenuTrigger> - <DropdownMenuContent className="w-56"> - {/* <DropdownMenuItem> + const guest_token_headers = { + headers: { + "Content-Type": "application/json", + Authorization: "Bearer " + access_token, + }, + }; console.log("Access token ", access_token) + + console.log(supersetApiUrl + '/guest_token/') + console.log(guest_token_body) + console.log(guest_token_headers) + return await axios.post(supersetApiUrl + '/guest_token/', guest_token_body, guest_token_headers) + .then(dt => { + console.log("guestToken: ", dt.data['token']) + return dt.data['token'] + }) + .catch(error => console.log(error)) + } + + + async function getToken() { + //calling login to get access token + const login_body = { + password: "1", + provider: "db", + refresh: true, + username: "guest", + }; + + const login_headers = { + headers: { + "Content-Type": "application/json", + }, + }; + + console.log(supersetApiUrl + '/login') + const { data } = await axios.post(supersetApiUrl + '/login', login_body, login_headers) + const access_token = data['access_token'] + return access_token + + } + + + // console.log("ref: ", dashboardRef.current) + // if (dashboardRef.current !== null) { + // console.log("embeding") + // embed() + // } else { + // console.log("Not embeding") + // } + useEffect(() => { + const embed = async () => { + embedDashboard({ + id: dashboardId, // given by the Superset embedding UI + supersetDomain: supersetUrl, + mountPoint: document.getElementById("superset-container"), // html element in which iframe render + fetchGuestToken: () => fetchGuestTokenFromBackend(), + dashboardUiConfig: { + hideTitle: false, + hideChartControls: true, + hideTab: true, + filters: { + expanded: true, + }, + } + }); + } + console.log("ref: ", dashboardRef.current) + if (dashboardRef.current !== null) { + console.log("embeding") + embed() + + const iframe = document.querySelector("iframe") + console.log(iframe); + + if (iframe) { + iframe.style.width = '100%'; // Set the width as needed + iframe.style.minHeight = '70vw'; // Set the height as needed + iframe.style.overflow = 'hidden' + iframe.style.border = "0" + } + } else { + console.log("Not embeding") + } + }, [fetchGuestTokenFromBackend, getToken]) + + return isGettingInnovation || isGettingComment ? ( + <div>Loading...</div> + ) : errorGettingInnovation || errorGettingComments ? ( + <div>Something went wrong</div> + ) : ( + <main> + <section className="flex flex-col"> + <div className="flex justify-between items-center p-4"> + <h2 className="font-semibold text-3xl">{innovation?.title}</h2> + <DropdownMenu> + <DropdownMenuTrigger asChild> + <div className="hover:bg-accent rounded-full p-1"> + <EllipsisVertical /> + </div> + </DropdownMenuTrigger> + <DropdownMenuContent className="w-56"> + <DropdownMenuItem> + <SquarePen className="mr-2 h-4 w-4" /> + {/* TODO: URL generator */} + <Link href={`/dashboard/innovation/edit/${id}`}> + <span>Edit</span> + </Link> + </DropdownMenuItem> + <DropdownMenuItem className="hover:bg-destructive active:bg-destructive focus:bg-destructive hover:text-white active:text-white focus:text-white"> + <Trash2 className="mr-2 h-4 w-4" /> + <span>Delete</span> + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + </div> + + <p className="px-4 ">{innovation?.description}</p> + <div className="flex items-center justify-between mt-5 px-4 "> + <div className="flex items-center gap-3"> + <Avatar className="h-12 w-12"> + <AvatarImage src={innovation?.author.profile_picture} /> + <AvatarFallback className="p-2"> + {get_fallback_name( + innovation?.author.first_name, + innovation?.author.last_name + )} + </AvatarFallback> + </Avatar> + <div> + <p>{`${innovation?.author.first_name} ${innovation?.author.last_name}`}</p> + <p className="text-sm">{innovation?.author.email}</p> + </div> + </div> + + <div className="flex gap-2 md:gap-4"> + {innovation?.dashboard_link && ( + <Link href={innovation?.dashboard_link || ""}> + <Button className="rounded-full md:px-9"> Visit </Button> + </Link> + )} + {innovation?.dashboard_definitions && ( + <Link download href={innovation.dashboard_definitions}> + <Button className="rounded-full" variant={"outline"}> + Download Datasets + </Button> + </Link> + )} + </div> + </div> + <div className="flex p-4 my-2 justify-between bg-accent"> + <div className="flex gap-3"> + <span + className="flex" + onClick={innovation?.is_liked ? handleUnlike : handleLike} + > + {innovation?.is_liked ? ( + <Heart className="fill-red-500" /> + ) : ( + <Heart className="hover:fill-red-500" /> + )}{" "} + {innovation?.likes_number} + </span> + <span className="flex"> + <MessageCircle /> {innovation?.comments_number}{" "} + </span> + </div> + <span + className="flex" + onClick={ + innovation?.is_bookmarked ? handleUnbookmark : handleBookmark + } + > + {innovation?.is_bookmarked ? ( + <Bookmark className="fill-green-600" /> + ) : ( + <Bookmark /> + )} + </span> + </div> + </section> + <section> + {/* TODO: Dashboard display */} + <div id="superset-container" ref={dashboardRef} className="w-full"> + </div> + + {innovation?.dashboard_image ? ( + <Image + alt="Innovation Image" + width={500} + height={600} + src={innovation?.dashboard_image} + /> + ) : ( + <></> + )} + </section> + + <section className="px-6 pb-4"> + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> + <FormField + control={form.control} + name="message" + render={({ field }) => ( + <FormItem> + <FormLabel>Comment</FormLabel> + <FormControl> + <Textarea placeholder="Type comment here..." {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + <Button + className="rounded-full" + type="submit" + size={"lg"} + disabled={isCreatingComment} + > + Submit + </Button> + </form> + </Form> + </section> + {/* Comments container */} + <section className="p-7 space-y-4"> + {comments?.map((comment, index) => ( + <div className="border p-3 rounded-lg shadow-md" key={index}> + <div className="flex items-center justify-between"> + <div className="flex items-center gap-3"> + <Avatar className="h-12 w-12"> + <AvatarImage src={comment.author.profile_picture} /> + <AvatarFallback className="p-2"> + {get_fallback_name( + innovation?.author.first_name, + innovation?.author.last_name + )} + </AvatarFallback> + </Avatar> + <div> + <p> + {comment.author.first_name} {comment.author.last_name} + </p> + <p className="text-sm">{comment.author.email}</p> + </div> + </div> + <DropdownMenu> + <DropdownMenuTrigger asChild> + <div className="hover:bg-accent rounded-full p-1"> + <EllipsisVertical /> + </div> + </DropdownMenuTrigger> + <DropdownMenuContent className="w-56"> + {/* <DropdownMenuItem> <SquarePen className="mr-2 h-4 w-4" /> // TODO: Comment Editing <Link href={""}> <span>Edit</span> </Link> </DropdownMenuItem> */} - <DropdownMenuItem className="hover:bg-destructive active:bg-destructive focus:bg-destructive hover:text-white active:text-white focus:text-white"> - <Trash2 className="mr-2 h-4 w-4" /> - <span>Delete</span> - </DropdownMenuItem> - </DropdownMenuContent> - </DropdownMenu> - </div> - <Separator className="my-3" /> - <p>{comment.text}</p> - </div> - ))} - <PaginationDemo - currentPage={currentPage} - totalPages={totalPages ?? 0} - onPrevious={handlePrevious} - onNext={handleNext} - /> - </section> - </main> - ); + <DropdownMenuItem className="hover:bg-destructive active:bg-destructive focus:bg-destructive hover:text-white active:text-white focus:text-white"> + <Trash2 className="mr-2 h-4 w-4" /> + <span>Delete</span> + </DropdownMenuItem> + </DropdownMenuContent> + </DropdownMenu> + </div> + <Separator className="my-3" /> + <p>{comment.text}</p> + </div> + ))} + <PaginationDemo + currentPage={currentPage} + totalPages={totalPages ?? 0} + onPrevious={handlePrevious} + onNext={handleNext} + /> + </section> + </main> + ); }; export default InnovationDetailPage; diff --git a/superset-embed b/superset-embed new file mode 160000 index 0000000..698e9b9 --- /dev/null +++ b/superset-embed @@ -0,0 +1 @@ +Subproject commit 698e9b95593ec7b6a648ef79965c54d39f746c6f From 8d89210876f3f2e77c7a74522054ceef04a3478a Mon Sep 17 00:00:00 2001 From: Karume-lab <danielkarume@outlook.com> Date: Thu, 6 Jun 2024 12:47:23 +0300 Subject: [PATCH 2/2] fix: :adhesive_bandage: remove repo --- superset-embed | 1 - 1 file changed, 1 deletion(-) delete mode 160000 superset-embed diff --git a/superset-embed b/superset-embed deleted file mode 160000 index 698e9b9..0000000 --- a/superset-embed +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 698e9b95593ec7b6a648ef79965c54d39f746c6f