diff --git a/commit/commit/doctype/commit_docs/commit_docs.py b/commit/commit/doctype/commit_docs/commit_docs.py index 5f493ae..152e3bd 100644 --- a/commit/commit/doctype/commit_docs/commit_docs.py +++ b/commit/commit/doctype/commit_docs/commit_docs.py @@ -51,6 +51,33 @@ def get_docs_sidebar_parent_labels(id:str): return parent_labels_obj +@frappe.whitelist() +def get_all_commit_docs_detail(): + ''' + Get the All Commit Docs Details which are Published + # 1. Get the Commit Docs Document from the route + # 2. Check if the Commit Docs Document Published + # 3. Return the Commit Docs Document + # 4. Get The Sidebar Items for the Commit Docs + # 5. Return the Sidebar Items + ''' + + # Get All the Commit Docs which are Published + all_commit_docs = frappe.get_all('Commit Docs',{'published':1},'name') + + # Maintain the Commit Docs Object + commit_docs_obj = {} + + for commit_docs in all_commit_docs: + commit_docs = frappe.get_doc('Commit Docs',commit_docs.name).as_dict() + + parse_doc = parse_commit_docs(commit_docs) + + commit_docs_obj[commit_docs['route']] = parse_doc + + return commit_docs_obj + + @frappe.whitelist(allow_guest=True) def get_commit_docs_details(route:str): ''' @@ -67,35 +94,11 @@ def get_commit_docs_details(route:str): # Check if the document is published if frappe.db.get_value('Commit Docs',{'route':route},'published'): - # Get the Commit Docs Document commit_docs = frappe.get_doc('Commit Docs',{'route':route}).as_dict() - # Maintain route_map from the sidebar where key is the route and value is the name of the page - route_map = {} - - # Get the Sidebar Items - sidebar_items, route_map = get_sidebar_items(commit_docs.sidebar,route_map) - - # Get the Footer Items - footer_items = get_footer_items(commit_docs.footer) - - # Get the Navbar Items - navbar_items = get_navbar_items(commit_docs.navbar_items) + return parse_commit_docs(commit_docs) - # remove the sidebar from the commit_docs as it is not needed - commit_docs.pop('sidebar') - commit_docs.pop('footer') - commit_docs.pop('navbar_items') - - return { - 'commit_docs': commit_docs, - 'sidebar_items': sidebar_items, - 'footer_items': footer_items, - 'navbar_items': navbar_items, - 'route_map': route_map - } - else: return frappe.throw('Docs Not Published') @@ -103,6 +106,32 @@ def get_commit_docs_details(route:str): return frappe.throw('Docs Not Found') +def parse_commit_docs(commit_docs): + # Maintain route_map from the sidebar where key is the route and value is the name of the page + route_map = {} + + # Get the Sidebar Items + sidebar_items, route_map = get_sidebar_items(commit_docs.sidebar,route_map) + + # Get the Footer Items + footer_items = get_footer_items(commit_docs.footer) + + # Get the Navbar Items + navbar_items = get_navbar_items(commit_docs.navbar_items) + + # remove the sidebar from the commit_docs as it is not needed + commit_docs.pop('sidebar') + commit_docs.pop('footer') + commit_docs.pop('navbar_items') + + return { + 'commit_docs': commit_docs, + 'sidebar_items': sidebar_items, + 'footer_items': footer_items, + 'navbar_items': navbar_items, + 'route_map': route_map + } + def get_footer_items(footer): ''' Get the Footer Items diff --git a/commit/commit/doctype/commit_docs_page/commit_docs_page.json b/commit/commit/doctype/commit_docs_page/commit_docs_page.json index 4110d98..989f952 100644 --- a/commit/commit/doctype/commit_docs_page/commit_docs_page.json +++ b/commit/commit/doctype/commit_docs_page/commit_docs_page.json @@ -1,133 +1,133 @@ { - "actions": [], - "allow_rename": 1, - "autoname": "format:{title}-{route}", - "creation": "2024-10-29 19:39:29.842455", - "doctype": "DocType", - "engine": "InnoDB", - "field_order": [ - "title", - "route", - "published", - "allow_guest", - "icon", - "column_break_sedp", - "badge", - "badge_color", - "is_group_page", - "documentation_section", - "content", - "section_break_twyn", - "linked_pages" - ], - "fields": [ - { - "fieldname": "title", - "fieldtype": "Data", - "in_list_view": 1, - "label": "Title", - "reqd": 1 - }, - { - "fieldname": "route", - "fieldtype": "Data", - "in_list_view": 1, - "in_preview": 1, - "in_standard_filter": 1, - "label": "Route", - "reqd": 1, - "unique": 1 - }, - { - "default": "1", - "fieldname": "published", - "fieldtype": "Check", - "label": "Published" - }, - { - "default": "1", - "fieldname": "allow_guest", - "fieldtype": "Check", - "label": "Allow Guest" - }, - { - "depends_on": "eval:doc.is_group_page == 0", - "fieldname": "content", - "fieldtype": "Markdown Editor", - "ignore_xss_filter": 1, - "label": "Content" - }, - { - "description": "This is badge field, eg: GET , POST etc.", - "fieldname": "badge", - "fieldtype": "Data", - "label": "Badge" - }, - { - "description": "Add Tailwind colours like red, green, blue, yellow, purple, pink, indigo, cyan, teal, lime, orange, gray etc.", - "fieldname": "badge_color", - "fieldtype": "Data", - "label": "Badge Color" - }, - { - "fieldname": "column_break_sedp", - "fieldtype": "Column Break" - }, - { - "default": "0", - "description": "When enabled, this page can hold and display nested sub-pages, creating a structured hierarchy in the sidebar.", - "fieldname": "is_group_page", - "fieldtype": "Check", - "label": "Is Group Page" - }, - { - "fieldname": "documentation_section", - "fieldtype": "Section Break", - "label": "Documentation" - }, - { - "description": "\"Supports only icons from the react-icons library. Enter the icon name in the format 'libraryPrefix/IconName' (e.g., 'Fa/FaFileExcel') to display it beside the title in the sidebar.\"\n", - "documentation_url": "https://react-icons.github.io/react-icons/search/", - "fieldname": "icon", - "fieldtype": "Data", - "label": "Icon" - }, - { - "fieldname": "section_break_twyn", - "fieldtype": "Section Break" - }, - { - "depends_on": "eval:doc.is_group_page == 1", - "fieldname": "linked_pages", - "fieldtype": "Table", - "label": "Linked Pages", - "options": "Linked Commit Docs Page" - } - ], - "index_web_pages_for_search": 1, - "links": [], - "modified": "2024-11-15 15:20:42.503563", - "modified_by": "Administrator", - "module": "commit", - "name": "Commit Docs Page", - "naming_rule": "Expression", - "owner": "Administrator", - "permissions": [ - { - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "System Manager", - "share": 1, - "write": 1 - } - ], - "sort_field": "creation", - "sort_order": "DESC", - "states": [], - "title_field": "title" + "actions": [], + "allow_rename": 1, + "autoname": "format:{title}-{route}", + "creation": "2024-10-29 19:39:29.842455", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "title", + "route", + "published", + "allow_guest", + "icon", + "column_break_sedp", + "badge", + "badge_color", + "is_group_page", + "documentation_section", + "content", + "section_break_twyn", + "linked_pages" + ], + "fields": [ + { + "fieldname": "title", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Title", + "reqd": 1 + }, + { + "fieldname": "route", + "fieldtype": "Data", + "in_list_view": 1, + "in_preview": 1, + "in_standard_filter": 1, + "label": "Route", + "reqd": 1, + "unique": 1 + }, + { + "default": "1", + "fieldname": "published", + "fieldtype": "Check", + "label": "Published" + }, + { + "default": "1", + "fieldname": "allow_guest", + "fieldtype": "Check", + "label": "Allow Guest" + }, + { + "depends_on": "eval:doc.is_group_page == 0", + "fieldname": "content", + "fieldtype": "Markdown Editor", + "ignore_xss_filter": 1, + "label": "Content" + }, + { + "description": "This is badge field, eg: GET , POST etc.", + "fieldname": "badge", + "fieldtype": "Data", + "label": "Badge" + }, + { + "description": "Add Tailwind colours like red, green, blue, yellow, purple, pink, indigo, cyan, teal, lime, orange, gray etc.", + "fieldname": "badge_color", + "fieldtype": "Data", + "label": "Badge Color" + }, + { + "fieldname": "column_break_sedp", + "fieldtype": "Column Break" + }, + { + "default": "0", + "description": "When enabled, this page can hold and display nested sub-pages, creating a structured hierarchy in the sidebar.", + "fieldname": "is_group_page", + "fieldtype": "Check", + "label": "Is Group Page" + }, + { + "fieldname": "documentation_section", + "fieldtype": "Section Break", + "label": "Documentation" + }, + { + "description": "\"Supports only icons from the lucid-react library. Enter the icon name in the format 'libraryPrefix/IconName' (e.g., 'Fa/FaFileExcel') to display it beside the title in the sidebar.\"\n", + "documentation_url": "https://lucide.dev/icons", + "fieldname": "icon", + "fieldtype": "Data", + "label": "Icon" + }, + { + "fieldname": "section_break_twyn", + "fieldtype": "Section Break" + }, + { + "depends_on": "eval:doc.is_group_page == 1", + "fieldname": "linked_pages", + "fieldtype": "Table", + "label": "Linked Pages", + "options": "Linked Commit Docs Page" + } + ], + "index_web_pages_for_search": 1, + "links": [], + "modified": "2024-12-13 14:07:48.524842", + "modified_by": "Administrator", + "module": "commit", + "name": "Commit Docs Page", + "naming_rule": "Expression", + "owner": "Administrator", + "permissions": [ + { + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "share": 1, + "write": 1 + } + ], + "sort_field": "creation", + "sort_order": "DESC", + "states": [], + "title_field": "title" } \ No newline at end of file diff --git a/commit/commit/doctype/commit_docs_page/commit_docs_page.py b/commit/commit/doctype/commit_docs_page/commit_docs_page.py index e3bf74f..3726f55 100644 --- a/commit/commit/doctype/commit_docs_page/commit_docs_page.py +++ b/commit/commit/doctype/commit_docs_page/commit_docs_page.py @@ -93,7 +93,7 @@ def publish_documentation(project_branch, endpoint, viewer_type, docs_name, pare 'commit_docs': commit_docs.name } -@frappe.whitelist() +@frappe.whitelist(allow_guest=True) def get_commit_docs_page(name): ''' Get the Commit Docs Page diff --git a/commit/commit/doctype/commit_docs_topbar_item/commit_docs_topbar_item.json b/commit/commit/doctype/commit_docs_topbar_item/commit_docs_topbar_item.json index d2034da..fa2edf2 100644 --- a/commit/commit/doctype/commit_docs_topbar_item/commit_docs_topbar_item.json +++ b/commit/commit/doctype/commit_docs_topbar_item/commit_docs_topbar_item.json @@ -53,6 +53,7 @@ "label": "Parent Label" }, { + "description": "\"Supports only icons from the lucid-react library. Enter the icon name, eg:\"Bell\" to display it beside the title in the sidebar.\"\n", "fieldname": "icon", "fieldtype": "Data", "label": "Icon" @@ -73,7 +74,7 @@ "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2024-11-09 18:41:50.962807", + "modified": "2024-12-13 14:08:16.402492", "modified_by": "Administrator", "module": "commit", "name": "Commit Docs Topbar Item", diff --git a/commit/www/commit.py b/commit/www/commit.py index d92d51f..ced1b6a 100644 --- a/commit/www/commit.py +++ b/commit/www/commit.py @@ -2,19 +2,17 @@ import json import frappe.sessions import re - +from commit.api.meta_data import get_installed_apps +from commit.commit.doctype.commit_docs.commit_docs import get_all_commit_docs_detail no_cache = 1 SCRIPT_TAG_PATTERN = re.compile(r"\") CLOSING_SCRIPT_TAG_PATTERN = re.compile(r"") def get_context(context): - csrf_token = frappe.sessions.get_csrf_token() - frappe.db.commit() context = frappe._dict() context.boot = get_boot() - context.csrf_token = csrf_token context.build_version = frappe.utils.get_build_version() return context @@ -36,6 +34,8 @@ def get_boot(): show_system_apps = commit_settings.show_system_apps boot["show_system_apps"] = show_system_apps + boot["get_installed_apps"] = get_installed_apps() + boot["get_all_commit_docs_detail"] = get_all_commit_docs_detail() boot_json = frappe.as_json(boot, indent=None, separators=(",", ":")) boot_json = SCRIPT_TAG_PATTERN.sub("", boot_json) diff --git a/dashboard/index.html b/dashboard/index.html index 2eaa979..4d0e54f 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -9,6 +9,8 @@ + Commit - Developer tooling for the Frappeverse diff --git a/dashboard/package.json b/dashboard/package.json index 08fa1da..d97d157 100644 --- a/dashboard/package.json +++ b/dashboard/package.json @@ -53,20 +53,22 @@ "jotai": "^2.8.3", "lodash": "^4.17.21", "lodash.isplainobject": "^4.0.6", + "lucide-react": "^0.468.0", "moment-timezone": "^0.5.43", "react": "^18.2.0", "react-dom": "^18.2.0", "react-dropzone": "^14.2.3", "react-hook-form": "^7.45.1", - "react-icons": "^5.2.1", "react-router-dom": "^6.14.1", "reactflow": "^11.11.4", "rehype-katex": "^7.0.1", + "rehype-pretty-code": "^0.14.0", "rehype-raw": "^7.0.0", "remark-breaks": "^4.0.0", "remark-gfm": "^4.0.0", "remark-math": "^6.0.0", "shadcn-ui": "^0.8.0", + "shiki": "^1.24.3", "socket.io-client": "^4.5.1", "swr": "^2.1.5", "tailwind-merge": "^1.13.2", diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index d36d6e1..56702d0 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -1,13 +1,16 @@ import { FrappeProvider } from 'frappe-react-sdk' import { BrowserRouter, Route, Routes } from 'react-router-dom' -import { APIViewerContainer } from './pages/features/api_viewer/APIViewer' -import { Overview } from './pages/overview/Overview' -import { ERDViewer } from './pages/features/erd/ERDViewer' -import { AppAPIViewerContainer } from './pages/features/api_viewer/AppAPIViewer' -import { CreateERD } from './pages/features/erd/meta/CreateERDForMeta' -import ViewDocs from './pages/features/docs/ViewDocs' -import { PageNotFound } from './components/common/PageNotFound/PageNotFound' -import DocsPage from './pages/features/docs/DocsPage' +import { lazy, Suspense } from 'react' +import { FullPageLoader } from './components/common/FullPageLoader/FullPageLoader' + +const ERDViewer = lazy(async () => import('./pages/features/erd/ERDViewer')) +const Overview = lazy(async () => import('./pages/overview/Overview')) +const APIViewerContainer = lazy(async () => import('./pages/features/api_viewer/APIViewer')) +const AppAPIViewerContainer = lazy(async () => import('./pages/features/api_viewer/AppAPIViewer')) +const CreateERD = lazy(async () => import('./pages/features/erd/meta/CreateERDForMeta')) +const ViewDocs = lazy(async () => import('./pages/features/docs/ViewDocs')) +const PageNotFound = lazy(async () => import('./components/common/PageNotFound/PageNotFound')) +const DocsPage = lazy(async () => import('./pages/features/docs/DocsPage')) function App() { @@ -24,25 +27,27 @@ function App() { return ( + }> {/* */} - - {/** Public Routes */} - {/* } /> */} + + {/** Public Routes */} + {/* } /> */} - {/** Private Routes */} - {/* } /> */} - {/* default route on '/' */} - } /> - {/*TODO: Need to Change below route */} - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - + {/** Private Routes */} + {/* } /> */} + {/* default route on '/' */} + } /> + {/*TODO: Need to Change below route */} + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + {/* */} diff --git a/dashboard/src/components/common/AsyncDropdown/AsyncDropdown.tsx b/dashboard/src/components/common/AsyncDropdown/AsyncDropdown.tsx index 6e807bc..4eb76a8 100644 --- a/dashboard/src/components/common/AsyncDropdown/AsyncDropdown.tsx +++ b/dashboard/src/components/common/AsyncDropdown/AsyncDropdown.tsx @@ -1,5 +1,5 @@ import { FrappeError, useFrappePostCall } from 'frappe-react-sdk' -import { PropsWithChildren, useEffect, useRef } from 'react' +import { lazy, PropsWithChildren, Suspense, useEffect, useRef } from 'react' import { Filter, useFrappeGetCall } from "frappe-react-sdk"; import { useCallback, useMemo, useState } from "react"; import { RegisterOptions, useController, useFormContext } from "react-hook-form"; @@ -12,9 +12,11 @@ import { useDebounce } from '@/hooks/useDebounce'; import { getLinkTitleAtom, setLinkTitleAtom } from './LinkTitles'; import { AsyncSpinnerLoader } from '../FullPageLoader/SpinnerLoader'; import { getErrorMessages } from '../ErrorBanner/ErrorBanner'; -import MDXRenderer from '../MarkdownRenderer/MDX'; +import { FullPageLoader } from '../FullPageLoader/FullPageLoader'; +const MDXRenderer = lazy(() => import('../MarkdownRenderer/MDX')) + interface ResultItem { value: string, description: string, @@ -472,7 +474,9 @@ const ErrorContainer = ({ error }: { error?: FrappeError }) => {

- {getErrorMessages(error).map(e => )} + }> + {getErrorMessages(error).map(e => )} +

); diff --git a/dashboard/src/components/common/Checkbox/CreatableSelect.tsx b/dashboard/src/components/common/Checkbox/CreatableSelect.tsx index 4c46907..6c1b7a7 100644 --- a/dashboard/src/components/common/Checkbox/CreatableSelect.tsx +++ b/dashboard/src/components/common/Checkbox/CreatableSelect.tsx @@ -13,10 +13,9 @@ import { PopoverTrigger, } from '@/components/ui/popover'; import { ScrollArea } from '@/components/ui/scroll-area'; -import { MdAdd, MdCheck } from 'react-icons/md'; -import { LuChevronsUpDown } from 'react-icons/lu'; import { Input } from '@/components/ui/input'; import { Controller, UseControllerProps, useFormContext } from 'react-hook-form'; +import { Check, ChevronsUpDown, Plus } from 'lucide-react'; export type ComboboxOptions = { value: string; @@ -76,7 +75,7 @@ export const CreatableSelect = ({ options, selected, className, label, mode = 's ) : ( `Select ${label ?? 'Item'}` )} - + @@ -111,7 +110,7 @@ export const CreatableSelect = ({ options, selected, className, label, mode = 's } }} > - + )} @@ -218,7 +217,7 @@ export const FormCreatableSelect = ({ ) : ( `Select ${label ?? 'Item'}` )} - + @@ -246,7 +245,7 @@ export const FormCreatableSelect = ({ } }} > - setIsCreating(true)} > {`Add ${label ?? 'Item'}`} - + )} diff --git a/dashboard/src/components/common/DynamicIconImport/IconComponent.tsx b/dashboard/src/components/common/DynamicIconImport/IconComponent.tsx index 7979661..f11595c 100644 --- a/dashboard/src/components/common/DynamicIconImport/IconComponent.tsx +++ b/dashboard/src/components/common/DynamicIconImport/IconComponent.tsx @@ -1,82 +1,65 @@ -import { CSSProperties, lazy, Suspense, SVGAttributes, useMemo } from "react"; -import { IconContext } from "react-icons"; +import React, { CSSProperties, lazy, Suspense, SVGAttributes, useMemo } from 'react'; -interface IProps { +interface LucideDynamicIconProps { icon: string; color?: string; - size?: string; + size?: number | string; className?: string; style?: CSSProperties; + strokeWidth?: number; + absoluteStrokeWidth?: boolean; attr?: SVGAttributes; fallback?: JSX.Element | null; } + // Helper to load the icon -const loadIcon = async (icon: string) => { - const [library, iconName] = icon.split("/"); - const lib = library.toLowerCase(); - // Statically construct the import statement using a function map - // Full list of importable libraries from react-icons - const moduleImporters: Record Promise> = { - ai: () => import("react-icons/ai"), // Ant Design Icons - bs: () => import("react-icons/bs"), // Bootstrap Icons - bi: () => import("react-icons/bi"), // BoxIcons - ci: () => import("react-icons/ci"), // Circum Icons - cg: () => import("react-icons/cg"), // css.gg - di: () => import("react-icons/di"), // Devicons - fi: () => import("react-icons/fi"), // Feather Icons - fc: () => import("react-icons/fc"), // Flat Color Icons - fa: () => import("react-icons/fa"), // Font Awesome 5 Icons - fa6: () => import("react-icons/fa6"), // Font Awesome 6 Icons - gi: () => import("react-icons/gi"), // Game Icons - go: () => import("react-icons/go"), // GitHub Octicons - gr: () => import("react-icons/gr"), // Grommet Icons - hi: () => import("react-icons/hi"), // Heroicons - hi2: () => import("react-icons/hi2"), // Heroicons v2 - im: () => import("react-icons/im"), // IcoMoon Free - lia: () => import("react-icons/lia"), // Icons8 Line Awesome - io: () => import("react-icons/io"), // Ionicons - io5: () => import("react-icons/io5"), // Ionicons v5 - lu: () => import("react-icons/lu"), // Lucide Icons - md: () => import("react-icons/md"), // Material Design Icons - pi: () => import("react-icons/pi"), // Phosphor Icons - rx: () => import("react-icons/rx"), // Radix Icons - ri: () => import("react-icons/ri"), // Remix Icons - si: () => import("react-icons/si"), // Simple Icons - sl: () => import("react-icons/sl"), // Simple Line Icons - tb: () => import("react-icons/tb"), // Tabler Icons - tfi: () => import("react-icons/tfi"), // Themify Icons - ti: () => import("react-icons/ti"), // Typicons - vsc: () => import("react-icons/vsc"), // VS Code Icons - wi: () => import("react-icons/wi"), // Weather Icons - }; +const loadLucideIcon = async (iconName: string) => { + try { + const module: any = await import('lucide-react'); + const IconComponent = module[iconName]; + + if (!IconComponent) { + throw new Error(`Icon "${iconName}" not found in Lucide React library`); + } - const importer = moduleImporters[lib]; - if (!importer) throw new Error(`Icon library "${library}" is not supported.`); - const module = await importer() - const IconComponent = module[iconName] - if (!IconComponent) throw new Error(`Icon "${icon}" not found in "${library}".`) - return IconComponent + return IconComponent; + } catch (error) { + console.error('Failed to load Lucide icon:', error); + throw error; + } }; -const DynamicIcon: React.FC = ({ icon, color, size, className, style, attr, fallback = null }) => { +const DynamicIcon: React.FC = ({ + icon, + color, + size = 24, + className, + style, + strokeWidth, + absoluteStrokeWidth, + attr, + fallback = null +}) => { // Memoize the icon component so it's loaded only when `icon` changes const Icon = useMemo( - () => lazy(() => loadIcon(icon).then((component) => ({ default: component }))), + () => lazy(() => loadLucideIcon(icon).then((component) => ({ default: component }))), [icon] ); - const iconContext = { - color, - size, - className, - style, - attr, - }; + return ( - - - + ); }; + export default DynamicIcon; diff --git a/dashboard/src/components/common/ErrorBanner/ErrorBanner.tsx b/dashboard/src/components/common/ErrorBanner/ErrorBanner.tsx index 640316c..f7cee0e 100644 --- a/dashboard/src/components/common/ErrorBanner/ErrorBanner.tsx +++ b/dashboard/src/components/common/ErrorBanner/ErrorBanner.tsx @@ -1,7 +1,8 @@ import { FrappeError } from 'frappe-react-sdk' -import { useMemo } from 'react' -import MDXRenderer from '../MarkdownRenderer/MDX' +import { lazy, Suspense, useMemo } from 'react' +import { FullPageLoader } from '../FullPageLoader/FullPageLoader' +const MDXRenderer = lazy(() => import('../MarkdownRenderer/MDX')) interface ErrorBannerProps extends React.HTMLAttributes { error?: FrappeError | null, @@ -123,8 +124,10 @@ export const ErrorBanner = ({ error, overrideHeading, ...props }: ErrorBannerPro

+ }> {messages.map((m, i) => )} +

diff --git a/dashboard/src/components/common/Icons.ts b/dashboard/src/components/common/Icons.ts index 8de3f8a..45e3cbf 100644 --- a/dashboard/src/components/common/Icons.ts +++ b/dashboard/src/components/common/Icons.ts @@ -1,63 +1,48 @@ -import { IconType } from 'react-icons' -import { GrCurrency, GrFormAttachment, GrTextAlignFull } from 'react-icons/gr' -import { AiFillCode, AiFillFileImage, AiFillHtml5, AiOutlineHtml5, AiOutlineLink, AiOutlinePhone, AiOutlineStar, AiOutlineTable } from 'react-icons/ai' -import { BiBarcode, BiCheckboxChecked, BiColorFill, BiCurrentLocation, BiEdit, BiHeading, BiStopwatch, BiTime } from 'react-icons/bi' -import { BsBodyText, BsCalendarDate, BsFileEarmarkImage, BsFiletypeMdx, BsLink45Deg, BsMenuButton, BsPercent } from 'react-icons/bs' -import { TbTxt } from 'react-icons/tb' -import { HiOutlineLightBulb } from 'react-icons/hi' -import { TiSortNumerically } from 'react-icons/ti' -import { MdOutlineFunctions, MdOutlineNumbers } from 'react-icons/md' -import { FaIcons } from 'react-icons/fa' -import { VscJson } from 'react-icons/vsc' -import { RiLockPasswordLine } from 'react-icons/ri' -import { CiRead } from 'react-icons/ci' -import { IoIosArrowDropdown } from 'react-icons/io' -import { PiSignatureLight } from 'react-icons/pi' -import { LuText } from 'react-icons/lu' +import { ArrowUp01, Barcode, Calendar, CalendarClock, Check, Clock3, Code, FileCode, FileDigit, FileJson, Grid3x3, Heading, Heading1, Image, IndianRupee, LetterText, Lightbulb, Link, Link2, MapPinned, Menu, MousePointer2, PaintBucket, Paperclip, Parentheses, Pencil, PenOff, Percent, Phone, RectangleEllipsis, ScrollText, Signature, SquareStack, Star, Table, Timer, TypeOutline } from 'lucide-react' export type ICON_KEY = 'Autocomplete' | 'Attach' | 'Attach Image' | 'Barcode' | 'Button' | 'Check' | 'Code' | 'Color' | 'Currency' | 'Data' | 'Date' | 'Datetime' | 'Duration' | 'Dynamic Link' | 'Float' | 'Fold' | 'Geolocation' | 'Heading' | 'HTML' | 'HTML Editor' | 'Icon' | 'Image' | 'Int' | 'JSON' | 'Link' | 'Long Text' | 'Markdown Editor' | 'Password' | 'Percent' | 'Phone' | 'Read Only' | 'Rating' | 'Select' | 'Signature' | 'Small Text' | 'Table' | 'Table MultiSelect' | 'Text' | 'Text Editor' | 'Time' -export const ICON_KEY_MAP: Record = { - 'Autocomplete': HiOutlineLightBulb as IconType, - 'Attach': GrFormAttachment as IconType, - 'Attach Image': AiFillFileImage as IconType, - 'Barcode': BiBarcode as IconType, - 'Button': BsMenuButton as IconType, - 'Check': BiCheckboxChecked as IconType, - 'Code': AiFillCode as IconType, - 'Color': BiColorFill as IconType, - 'Currency': GrCurrency as IconType, - 'Data': TbTxt as IconType, - 'Date': BsCalendarDate as IconType, - 'Datetime': BsCalendarDate as IconType, - 'Duration': BiStopwatch as IconType, - 'Dynamic Link': BsLink45Deg as IconType, - 'Float': TiSortNumerically as IconType, - 'Fold': MdOutlineFunctions as IconType, - 'Geolocation': BiCurrentLocation as IconType, - 'Heading': BiHeading as IconType, - 'HTML': AiOutlineHtml5 as IconType, - 'HTML Editor': AiFillHtml5 as IconType, - 'Icon': FaIcons as IconType, - 'Image': BsFileEarmarkImage as IconType, - 'Int': MdOutlineNumbers as IconType, - 'JSON': VscJson as IconType, - 'Link': AiOutlineLink as IconType, - 'Long Text': BsBodyText as IconType, - 'Markdown Editor': BsFiletypeMdx as IconType, - 'Password': RiLockPasswordLine as IconType, - 'Percent': BsPercent as IconType, - 'Phone': AiOutlinePhone as IconType, - 'Read Only': CiRead as IconType, - 'Rating': AiOutlineStar as IconType, - 'Select': IoIosArrowDropdown as IconType, - 'Signature': PiSignatureLight as IconType, - 'Small Text': LuText as IconType, - 'Table': AiOutlineTable as IconType, - 'Table MultiSelect': AiOutlineTable as IconType, - 'Text': GrTextAlignFull as IconType, - 'Text Editor': BiEdit as IconType, - 'Time': BiTime as IconType, +export const ICON_KEY_MAP: Record = { + 'Autocomplete': Lightbulb as any, + 'Attach': Paperclip as any, + 'Attach Image': Image as any, + 'Barcode': Barcode as any, + 'Button': Menu as any, + 'Check': Check as any, + 'Code': Code as any, + 'Color': PaintBucket as any, + 'Currency': IndianRupee as any, + 'Data': TypeOutline as any, + 'Date': Calendar as any, + 'Datetime': CalendarClock as any, + 'Duration': Timer as any, + 'Dynamic Link': Link as any, + 'Float': ArrowUp01 as any, + 'Fold': Parentheses as any, + 'Geolocation': MapPinned as any, + 'Heading': Heading1 as any, + 'HTML': Heading as any, + 'HTML Editor': FileCode as any, + 'Icon': SquareStack as any, + 'Image': Image as any, + 'Int': FileDigit as any, + 'JSON': FileJson as any, + 'Link': Link2 as any, + 'Long Text': ScrollText as any, + 'Markdown Editor': Heading1 as any, + 'Password': RectangleEllipsis as any, + 'Percent': Percent as any, + 'Phone': Phone as any, + 'Read Only': PenOff as any, + 'Rating': Star as any, + 'Select': MousePointer2 as any, + 'Signature': Signature as any, + 'Small Text': LetterText as any, + 'Table': Table as any, + 'Table MultiSelect': Grid3x3 as any, + 'Text': LetterText as any, + 'Text Editor': Pencil as any, + 'Time': Clock3 as any, } diff --git a/dashboard/src/components/common/ImageUploader2/FileDrop.tsx b/dashboard/src/components/common/ImageUploader2/FileDrop.tsx index 4683ac7..018942a 100644 --- a/dashboard/src/components/common/ImageUploader2/FileDrop.tsx +++ b/dashboard/src/components/common/ImageUploader2/FileDrop.tsx @@ -1,12 +1,9 @@ import { Accept, useDropzone } from "react-dropzone" -import { MdOutlineDevices } from "react-icons/md" import { useEffect, useState } from "react" import { CustomFile } from "./ImageUploader" import { useToast } from "@/components/ui/use-toast" import { Button } from "@/components/ui/button" -import { TbTrash } from "react-icons/tb" -import { FiFile, FiLink } from 'react-icons/fi' -import { IoMdCheckmark } from "react-icons/io" +import { Check, MonitorSmartphone, Trash2, File as LucidFile, Link } from "lucide-react" export interface FileDropProps extends React.HTMLAttributes { @@ -87,7 +84,7 @@ export const FileDrop = ({ files, onFileChange, maxFiles = 1, uploading, accept,

Drag 'n' drop your files here.

@@ -128,7 +125,7 @@ export const FileListItem = ({ file, removeFile, isUploading, ...props }: FileLi {previewURL ? ( File preview ) : ( - file.fileType === 'file' ? : + file.fileType === 'file' ? : )}
@@ -140,10 +137,10 @@ export const FileListItem = ({ file, removeFile, isUploading, ...props }: FileLi
{isUploading ? ( - + ) : ( )}
diff --git a/dashboard/src/components/common/ImageUploader2/ImageUploader.tsx b/dashboard/src/components/common/ImageUploader2/ImageUploader.tsx index e49d7d3..0fbed14 100644 --- a/dashboard/src/components/common/ImageUploader2/ImageUploader.tsx +++ b/dashboard/src/components/common/ImageUploader2/ImageUploader.tsx @@ -1,6 +1,5 @@ import { useFrappeUpdateDoc } from "frappe-react-sdk" import { Accept } from "react-dropzone" -import { MdOutlineFileUpload } from 'react-icons/md' import { useState } from "react" import { useToast } from "@/components/ui/use-toast" import { File } from "@/types/Core/File" @@ -11,6 +10,7 @@ import { SpinnerLoader } from "../FullPageLoader/SpinnerLoader" import { DocumentUploadModal } from "./DocumentUploadModal" import { cn } from "@/lib/utils" import { useGetFilePreviewUrl } from "./FileDrop" +import { Upload } from "lucide-react" /** * Custom File Type for FILE UPLOADER component; with 'fileID' for unique ID & 'preview' for blob URL. @@ -136,7 +136,7 @@ export const ImageUploader = ({ file, doctype, docname, onUpdate, fieldname = 'i : updatingDoc ?
:
- {icon ? icon : } + {icon ? icon : }
} {deleteImage && } diff --git a/dashboard/src/components/common/MarkdownRenderer/MDX.tsx b/dashboard/src/components/common/MarkdownRenderer/MDX.tsx index 01953e7..d859546 100644 --- a/dashboard/src/components/common/MarkdownRenderer/MDX.tsx +++ b/dashboard/src/components/common/MarkdownRenderer/MDX.tsx @@ -13,6 +13,7 @@ import rehypeKatex from 'rehype-katex'; import rehypeSlug from 'rehype-slug'; import CustomHeading from '@/components/features/custommdxcomponent/CustomHeading'; import CustomCodeBlock from '@/components/features/custommdxcomponent/CustomCodeBlock'; +import rehypePrettyCode from "rehype-pretty-code"; // Custom components const CustomParagraph = ({ children }: { children?: React.ReactNode }) => { @@ -42,7 +43,7 @@ const compileMDX = async (mdxContent: string) => { const compiled = await compile(mdxContent, { outputFormat: 'function-body', remarkPlugins: [remarkMdx, remarkMath, remarkBreaks, remarkGfm], - rehypePlugins: [rehypeSlug, rehypeKatex], + rehypePlugins: [rehypeSlug, rehypeKatex, rehypePrettyCode], }); return String(compiled); }; diff --git a/dashboard/src/components/common/MarkdownRenderer/markdown.css b/dashboard/src/components/common/MarkdownRenderer/markdown.css index d452b8d..6ceaff0 100644 --- a/dashboard/src/components/common/MarkdownRenderer/markdown.css +++ b/dashboard/src/components/common/MarkdownRenderer/markdown.css @@ -237,10 +237,10 @@ font-size: 1em; } - .markdown-body figure { + /* .markdown-body figure { margin: 1em var(--base-size-40); } - + */ .markdown-body hr { box-sizing: content-box; overflow: hidden; @@ -829,7 +829,7 @@ text-decoration: inherit; } - .markdown-body samp { + .markdown-body samp { font-size: 85%; } @@ -838,10 +838,10 @@ } .markdown-body pre>code { - padding: 0; + padding: 4px; margin: 0; word-break: normal; - white-space: pre; + /* white-space: pre; */ background: transparent; border: 0; } @@ -870,8 +870,8 @@ .markdown-body pre tt { display: inline; max-width: auto; - padding: 0; - margin: 0; + padding: 2px; + margin: 2px; overflow: visible; line-height: inherit; word-wrap: normal; diff --git a/dashboard/src/components/common/PageNotFound/PageNotFound.tsx b/dashboard/src/components/common/PageNotFound/PageNotFound.tsx index d126f03..2e097d5 100644 --- a/dashboard/src/components/common/PageNotFound/PageNotFound.tsx +++ b/dashboard/src/components/common/PageNotFound/PageNotFound.tsx @@ -1,9 +1,9 @@ import { motion } from 'framer-motion'; import { Button } from "@/components/ui/button"; -import { IoCloudOutline } from "react-icons/io5"; import { useNavigate } from 'react-router-dom'; +import { Cloud } from 'lucide-react'; -export const PageNotFound = () => { +const PageNotFound = () => { const navigate = useNavigate() @@ -33,7 +33,7 @@ export const PageNotFound = () => { transition={{ duration: 1.2, ease: 'easeInOut' }} className="mb-10" > - + { ); -} \ No newline at end of file +} + +export default PageNotFound; \ No newline at end of file diff --git a/dashboard/src/components/features/APIClient/APIClientContent.tsx b/dashboard/src/components/features/APIClient/APIClientContent.tsx index 08c95cd..8472e78 100644 --- a/dashboard/src/components/features/APIClient/APIClientContent.tsx +++ b/dashboard/src/components/features/APIClient/APIClientContent.tsx @@ -6,10 +6,9 @@ import { Input } from "@/components/ui/input" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Argument } from "@/types/APIData" import { FrappeConfig, FrappeContext } from "frappe-react-sdk" +import { ChevronDown, Plus } from "lucide-react" import { useCallback, useContext, useEffect, useState } from "react" import { FormProvider, useForm } from "react-hook-form" -import { FaCaretDown } from "react-icons/fa" -import { IoAdd } from "react-icons/io5"; export interface APIClientContentProps { @@ -18,7 +17,7 @@ export interface APIClientContentProps { open: boolean } -export const APIClientContent = ({ endpoint, open, parameters }: APIClientContentProps) => { +const APIClientContent = ({ endpoint, open, parameters }: APIClientContentProps) => { const [requestType, setRequestType] = useState<"GET" | "POST">('GET') @@ -164,7 +163,7 @@ export const APIClientContent = ({ endpoint, open, parameters }: APIClientConten className="rounded-r-none w-[12ch]" > {requestType} - + @@ -196,7 +195,7 @@ export const APIClientContent = ({ endpoint, open, parameters }: APIClientConten className="w-[14ch]" > {paramsType === 'params' ? 'Params' : 'Form Data'} - + @@ -256,7 +255,7 @@ export const APIClientContent = ({ endpoint, open, parameters }: APIClientConten + }} variant="outline">Add Param } @@ -281,4 +280,6 @@ export const APIClientContent = ({ endpoint, open, parameters }: APIClientConten ) -} \ No newline at end of file +} + +export default APIClientContent \ No newline at end of file diff --git a/dashboard/src/components/features/api_viewer/APIDetails.tsx b/dashboard/src/components/features/api_viewer/APIDetails.tsx index 3245c83..49825b1 100644 --- a/dashboard/src/components/features/api_viewer/APIDetails.tsx +++ b/dashboard/src/components/features/api_viewer/APIDetails.tsx @@ -6,17 +6,17 @@ import { Button } from "@/components/ui/button" import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { web_url } from "@/config/socket" import { APIData, Argument } from "@/types/APIData" -import { XMarkIcon } from "@heroicons/react/24/outline" import { useFrappeGetCall } from "frappe-react-sdk" -import { useMemo, useState } from "react" -import { MdOutlineFileDownload } from "react-icons/md" -import { APIDocumentationOfSiteApp } from "../documentation/APIDocumentation" +import { lazy, Suspense, useMemo, useState } from "react" import { Dialog } from "@/components/ui/dialog" -import { APIClientContent } from "../APIClient/APIClientContent" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" -import { AiOutlineThunderbolt } from "react-icons/ai" +import { Download, X, Zap } from "lucide-react" -export const APIDetails = ({ project_branch, endpointData, selectedEndpoint, setSelectedEndpoint, viewerType, mutate }: { project_branch: string, endpointData: APIData[], selectedEndpoint: string, setSelectedEndpoint: React.Dispatch>, viewerType: string, mutate: () => void }) => { + +const APIDocumentationOfSiteApp = lazy(() => import('../documentation/APIDocumentation')) +const APIClientContent = lazy(() => import('../APIClient/APIClientContent')) + +const APIDetails = ({ project_branch, endpointData, selectedEndpoint, setSelectedEndpoint, viewerType, mutate }: { project_branch: string, endpointData: APIData[], selectedEndpoint: string, setSelectedEndpoint: React.Dispatch>, viewerType: string, mutate: () => void }) => { const data = useMemo(() => { return endpointData.find((endpoint: APIData) => endpoint.name === selectedEndpoint) }, [endpointData, selectedEndpoint]) @@ -73,7 +73,7 @@ export const APIDetails = ({ project_branch, endpointData, selectedEndpoint, set > Close panel -