diff --git a/src/ContentProcessorWeb/src/App.tsx b/src/ContentProcessorWeb/src/App.tsx index 06462b52..11b53f8e 100644 --- a/src/ContentProcessorWeb/src/App.tsx +++ b/src/ContentProcessorWeb/src/App.tsx @@ -2,7 +2,6 @@ import * as React from "react"; import { useEffect } from "react"; import Header from "./Components/Header/Header.tsx"; // Import Header import "./Styles/App.css"; -import "./Components/Content/Content.css"; import HomePage from "./Pages/HomePage.tsx"; import DefaultPage from "./Pages/DefaultPage"; //import AuxiliaryPage from "./Pages/AuxiliaryPage/AuxiliaryPage.tsx"; diff --git a/src/ContentProcessorWeb/src/Components/Content/Content.css b/src/ContentProcessorWeb/src/Components/Content/Content.css deleted file mode 100644 index 125fd66d..00000000 --- a/src/ContentProcessorWeb/src/Components/Content/Content.css +++ /dev/null @@ -1,19 +0,0 @@ -.contentToolbar { - width: calc(100% - 6px); - box-sizing: border-box; - display: flex; - flex: 1; - justify-content: space-between; - align-items: center; - padding: 16px; - height: 64px; - backdrop-filter: saturate(180%) blur(16px); - transition: all 0.3s cubic-bezier(0.215, 0.61, 0.355, 1); - z-index: 1; -} - -.contentToolbarTitleGroupLeft, -.contentToolbarTitleGroupRight { - display: flex; - align-items: center; -} diff --git a/src/ContentProcessorWeb/src/Components/Content/Content.tsx b/src/ContentProcessorWeb/src/Components/Content/Content.tsx deleted file mode 100644 index 6be16822..00000000 --- a/src/ContentProcessorWeb/src/Components/Content/Content.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import "../../Styles/App.css"; -import { Toolbar, ToolbarButton } from "@fluentui/react-components"; -import { Link } from "../../Imports/bundleIcons.tsx"; -import { useContentHooks } from "../../Hooks/useContentHooks.tsx"; -import ContentToolbar from "../../Hooks/useContentToolbarHooks.tsx"; - -// Visit https://mochimilk.github.io/cto_coral_docs/index.html#/developers/content for documentation - -interface ContentProps { - isPanelOpen: boolean; - togglePanel?: () => void; // Optional to conditionally render left toggle - isRightPanelOpen: boolean; - toggleRightPanel?: () => void; // Optional to conditionally render left toggle -} - -const ContentDevelopers: React.FC = ({ - isPanelOpen, - togglePanel, - isRightPanelOpen, - toggleRightPanel, -}) => { - const { commandKey } = useContentHooks({ togglePanel, toggleRightPanel }); - - return ( -
- {/*📌 Below is the setup for the content toolbar. - ***You may remove this if your app doesn't need a toolbar. */} - - - - }> - - - - - -
- {/* Populate content */} -
-
- ); -}; - -export default ContentDevelopers; diff --git a/src/ContentProcessorWeb/src/Components/DialogComponent/DialogComponent.tsx b/src/ContentProcessorWeb/src/Components/DialogComponent/DialogComponent.tsx index be2b439b..8a63e342 100644 --- a/src/ContentProcessorWeb/src/Components/DialogComponent/DialogComponent.tsx +++ b/src/ContentProcessorWeb/src/Components/DialogComponent/DialogComponent.tsx @@ -10,19 +10,8 @@ import { useId, } from "@fluentui/react-components"; -interface FooterButton { - text: string; - appearance: "primary" | "secondary"; - onClick: () => void; -} +import { ConfirmationProps } from './DialogComponentTypes' -interface ConfirmationProps { - title: string; - content: string; - isDialogOpen: boolean; // Controlled state for dialog visibility - onDialogClose: () => void; // Function to close the dialog - footerButtons: FooterButton[]; // Array of footer buttons -} export const Confirmation: React.FC = ({ title, diff --git a/src/ContentProcessorWeb/src/Components/DialogComponent/DialogComponentTypes.ts b/src/ContentProcessorWeb/src/Components/DialogComponent/DialogComponentTypes.ts new file mode 100644 index 00000000..02b4349e --- /dev/null +++ b/src/ContentProcessorWeb/src/Components/DialogComponent/DialogComponentTypes.ts @@ -0,0 +1,16 @@ + +import { ReactNode } from 'react'; + +interface FooterButton { + text: string; + appearance: "primary" | "secondary"; + onClick: () => void; +} + +export interface ConfirmationProps { + title: string; + content: string | ReactNode; + isDialogOpen: boolean; // Controlled state for dialog visibility + onDialogClose: () => void; // Function to close the dialog + footerButtons: FooterButton[]; // Array of footer buttons +} \ No newline at end of file diff --git a/src/ContentProcessorWeb/src/Components/DocumentViewer/DocumentViewer.tsx b/src/ContentProcessorWeb/src/Components/DocumentViewer/DocumentViewer.tsx index 9a32ef91..89e60a9b 100644 --- a/src/ContentProcessorWeb/src/Components/DocumentViewer/DocumentViewer.tsx +++ b/src/ContentProcessorWeb/src/Components/DocumentViewer/DocumentViewer.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; -import { Document } from "./DocumentViewer.types"; import { TIFFViewer } from 'react-tiff'; import './DocumentViewer.styles.scss'; @@ -107,7 +106,7 @@ const DocumentViewer = ({ className, metadata, urlWithSasToken, iframeKey }: IIF
We can't open this file

Something went wrong.

-
+ : getContentComponent() } diff --git a/src/ContentProcessorWeb/src/Components/DocumentViewer/DocumentViewer.types.ts b/src/ContentProcessorWeb/src/Components/DocumentViewer/DocumentViewer.types.ts deleted file mode 100644 index c5d94910..00000000 --- a/src/ContentProcessorWeb/src/Components/DocumentViewer/DocumentViewer.types.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { SlotRenderFunction } from "@fluentui/react-components" -import { DetailedHTMLProps, HTMLAttributes, JSXElementConstructor, ReactElement, ReactNode, ReactPortal, RefObject } from "react" -// Removed import for ReactI18NextChildren as it is not exported by react-i18next - - -export interface Document { - page_number: ((string | number | boolean | ReactPortal | ReactElement> | Iterable) & (string | number | boolean | ReactPortal | ReactElement> | Iterable | SlotRenderFunction, HTMLSpanElement>, "ref"> & { ref?: ((instance: HTMLSpanElement | null) => void) | RefObject | null | undefined }>)) | null | undefined - processId: string; // Unique document identifier - fileName: string; // Name of the file - keywords: { // Keywords object with dynamic keys and comma-separated string values - [key: string]: string; - }; - importedTime: string; // ISO timestamp for when the document was imported - processingTime: string; // Time taken to process the document - mimeType: string; // MIME type of the document (e.g., PDF, DOCX) - summary: string; // Summary of the document's contents - id: string; // Additional identifier - __partitionkey: string; // Partition key (specific to your data structure) - // index_key: string - // metadata_storage_path: string - // metadata_storage_name: string - // metadata_storage_size: number - // metadata_storage_content_md5: string - // content_size: number - // content_encoding: any - // description: any - // creation_date: string - // last_modified: string - // processing_date: any - // source_processing_date: string - // source_last_modified: string - // key_phrases: string[] - // topics: any[] - // organizations: string[] - // persons: string[] - // locations: string[] - // cities: string[] - // countries: string[] - // language: string - // translated_language: string - // paragraphs_count: number - // summary: string[] - // categories: any[] - // captions: any[] - // title: string - // translated_title: string - // author: string - // content_type: string - // content_group: string - // page_number: number - // page_count: any - // slide_count: any - // links: any[] - // emails: any[] - // // Index_key -> document Id - // // imageUrl - // // Filename - // // Filelocation - // // Tags - // // Uploadtime - // // LatestProcessTime - // // Status - // // Chat history id per document? - // document_id: string - // document_filename: string - document_url: string - // document_segments: string[] - // markets: any[] - // competitions: any[] - // technologies: any[] - // user_keywords: any[] - // user_categories: any[] - // user_tags: any[] - // strategies: any[] - // tables: string[] - // tables_count: number - // kvs: string - // kvs_count: number - // geolocation: any - // restricted: boolean - // parent_id: any - // chunk: any - // vector: any[] - // parent: Parent - // image: Image - // email: any - // document: Document2 - } \ No newline at end of file diff --git a/src/ContentProcessorWeb/src/Components/Header/Header.tsx b/src/ContentProcessorWeb/src/Components/Header/Header.tsx index ef59d6e7..2e4cce41 100644 --- a/src/ContentProcessorWeb/src/Components/Header/Header.tsx +++ b/src/ContentProcessorWeb/src/Components/Header/Header.tsx @@ -26,9 +26,12 @@ import { } from "../../Imports/bundleIcons.tsx"; import MainLogo from "../../Imports/MainLogo.svg"; import "./Header.css"; -import { DocumentBulletListCubeRegular, InfoRegular} from "@fluentui/react-icons" +import { DocumentBulletListCubeRegular, InfoRegular, DocumentData16Regular } from "@fluentui/react-icons" import useAuth from "../../msal-auth/useAuth.ts"; +import { useSelector, shallowEqual } from 'react-redux'; +import { RootState } from '../../store/index.ts'; +import useSwaggerPreview from "../../Hooks/useSwaggerPreview.ts"; interface HeaderPageProps { toggleTheme: () => void; @@ -41,6 +44,12 @@ const tabConfigs = [ value: "default", // Route path defined in App.tsx label: "Content", // Visible label on UI }, + + { + icon: , // Import bundle icon + value: "api", // Route path defined in App.tsx + label: "API Documentation", // Visible label on UI + }, // Add more ]; @@ -48,6 +57,10 @@ const HeaderPage: React.FC = ({ toggleTheme, isDarkMode }) => { const { shortcutLabel } = useHeaderHooks({ toggleTheme, isDarkMode }); const { user, logout, getToken } = useAuth(); + const { openSwaggerUI } = useSwaggerPreview(); + const store = useSelector((state: RootState) => ({ + swaggerJSON: state.leftPanel.swaggerJSON, + }), shallowEqual); const navigate = useNavigate(); const location = useLocation(); @@ -69,12 +82,20 @@ const HeaderPage: React.FC = ({ toggleTheme, isDarkMode }) => { _: React.SyntheticEvent, data: { value: TabValue } ) => { - const newRoute = Object.keys(tabRoutes).find( - (key) => tabRoutes[key] === data.value - ); - if (newRoute) { - navigate(newRoute); + if (data.value == 'api') { + _.preventDefault(); + const apiUrl: string = process.env.REACT_APP_API_BASE_URL as string; + const token = localStorage.getItem('token') ?? undefined; + openSwaggerUI(store.swaggerJSON, apiUrl, token) + } else { + const newRoute = Object.keys(tabRoutes).find( + (key) => tabRoutes[key] === data.value + ); + if (newRoute) { + navigate(newRoute); + } } + }; @@ -100,8 +121,8 @@ const HeaderPage: React.FC = ({ toggleTheme, isDarkMode }) => {
- - AI-generated content may be incorrect + + AI-generated content may be incorrect
{/* Tools Section */} diff --git a/src/ContentProcessorWeb/src/Components/JSONEditor/JSONEditor.tsx b/src/ContentProcessorWeb/src/Components/JSONEditor/JSONEditor.tsx index 2760e7f4..cc61e2da 100644 --- a/src/ContentProcessorWeb/src/Components/JSONEditor/JSONEditor.tsx +++ b/src/ContentProcessorWeb/src/Components/JSONEditor/JSONEditor.tsx @@ -2,29 +2,33 @@ import React, { useEffect, useState } from 'react' import { JsonEditor, JsonEditorProps, githubDarkTheme } from 'json-edit-react' import './JSONEditor.styles.scss' -import { useDispatch, useSelector,shallowEqual } from 'react-redux'; +import { useDispatch, useSelector, shallowEqual } from 'react-redux'; import { AppDispatch, RootState } from '../../store'; import { fetchContentJsonData, setModifiedResult } from '../../store/slices/centerPanelSlice'; +import { SearchBox } from "@fluentui/react-components"; + interface JSONEditorProps { processId?: string | null; } const JSONEditor: React.FC = () => { const [jsonData, setJsonData] = React.useState({}) - + const [isFocused, setIsFocused] = useState(false); const dispatch = useDispatch(); + const [searchText, setSearchText] = useState(''); const store = useSelector((state: RootState) => ({ processId: state.leftPanel.processId, contentData: state.centerPanel.contentData, cLoader: state.centerPanel.cLoader, cError: state.centerPanel.cError, - }),shallowEqual ); + isJSONEditorSearchEnabled: state.centerPanel.isJSONEditorSearchEnabled + }), shallowEqual); useEffect(() => { - if(!store.cLoader){ + if (!store.cLoader) { if (Object.keys(store.contentData).length > 0) { const formattedJson = store.contentData.result; const data = { @@ -33,7 +37,7 @@ const JSONEditor: React.FC = () => { } } setJsonData(data); - }else { + } else { setJsonData({}) } } @@ -44,32 +48,59 @@ const JSONEditor: React.FC = () => { dispatch(setModifiedResult(newData)); } + const handleFocus = () => setIsFocused(true); + const handleBlur = () => setIsFocused(false); + return ( <>{ - store.cLoader ?

Loading...

: - Object.keys(jsonData).length == 0 ?

No data available

: - { - onUpdateHandle(newData) - }} - //setData={ setJsonData } // optional - restrictEdit={({ key, path, level, index, value, size, parentData, fullData, collapsed }) => { - return !path.includes('extracted_result') - } - } - restrictDelete={true} - /> + store.cLoader ?

Loading...

: + Object.keys(jsonData).length == 0 ?

No data available

: + <> + {store.isJSONEditorSearchEnabled && +
+ { setSearchText(data.value) }} + style={{ + width: isFocused ? '200px' : '100px', + transition: 'width 0.3s ease', + }} + /> +
} + { + onUpdateHandle(newData) + }} + //setData={ setJsonData } // optional + restrictEdit={({ key, path, level, index, value, size, parentData, fullData, collapsed }) => { + return !path.includes('extracted_result') + } + } + restrictDelete={true} + /> + } ) } diff --git a/src/ContentProcessorWeb/src/Components/JSONEditor/data.json b/src/ContentProcessorWeb/src/Components/JSONEditor/data.json deleted file mode 100644 index b5d0bc47..00000000 --- a/src/ContentProcessorWeb/src/Components/JSONEditor/data.json +++ /dev/null @@ -1,857 +0,0 @@ -{ - "extracted_result": { - "customer_name": "ALD AUTOMOTIVE P LTD.", - "customer_address": { - "street": "Workafella Business Centre 150/1, Infantry Road, Opp. Commissioner Office, Vasanth Nagar", - "city": "Bangalore", - "state": "Karnataka", - "postal_code": "560001", - "country": "India" - }, - "customer_tax_id": "29AAFCA0924K1ZN", - "shipping_address": null, - "purchase_order": null, - "invoice_id": "IATIEN1819013536", - "invoice_date": "2019-02-15", - "payable_by": null, - "vendor_name": "ADISHAKTI CARS PVT. LTD.", - "vendor_address": { - "street": "#56, OPP. LUMBINI GARDEN MAIN GATE, SERVICE RING ROAD, VEERANAPALYA MAIN ROAD", - "city": "BENGALURU", - "state": "Karnataka", - "postal_code": "560045", - "country": "India" - }, - "vendor_tax_id": "29AAHCS6672E1ZZ", - "remittance_address": null, - "subtotal": 350.0, - "total_discount": 0.0, - "total_tax": 63.0, - "invoice_total": 413.0, - "payment_terms": null, - "items": [ - { - "product_code": "FREE2", - "description": "SECOND FREE SERVICE", - "quantity": 1, - "tax": 0.0, - "tax_rate": "9%", - "unit_price": 500.0, - "total": 0.0, - "reason": null - }, - { - "product_code": "423030", - "description": "BRAKE BLEEDING", - "quantity": 1, - "tax": 0.0, - "tax_rate": "9%", - "unit_price": 0.0, - "total": 0.0, - "reason": null - }, - { - "product_code": "183090", - "description": "BREATHER REPLACEMENT", - "quantity": 1, - "tax": 0.0, - "tax_rate": "9%", - "unit_price": 0.0, - "total": 0.0, - "reason": null - }, - { - "product_code": "AKSPROPLUS", - "description": "SERVICE PLUS - AUTOKROM", - "quantity": 1, - "tax": 63.0, - "tax_rate": "9%", - "unit_price": 350.0, - "total": 413.0, - "reason": null - } - ], - "total_item_quantity": 4.0, - "items_customer_signature": { - "signatory": "ANIL DB", - "is_signed": true - }, - "items_vendor_signature": { - "signatory": "Authorized signatory", - "is_signed": true - }, - "returns": [], - "total_return_quantity": null, - "returns_customer_signature": null, - "returns_vendor_signature": null - }, - "confidence": { - "customer_name": { - "confidence": 0.988, - "value": "ALD AUTOMOTIVE P LTD." - }, - "customer_address": { - "street": { - "confidence": 0.993, - "value": "Workafella Business Centre 150/1, Infantry Road, Opp. Commissioner Office, Vasanth Nagar" - }, - "city": { - "confidence": 0.693, - "value": "Bangalore" - }, - "state": { - "confidence": 0.992, - "value": "Karnataka" - }, - "postal_code": { - "confidence": 0.679, - "value": "560001" - }, - "country": { - "confidence": 0.953, - "value": "India" - } - }, - "customer_tax_id": { - "confidence": 0.989, - "value": "29AAFCA0924K1ZN" - }, - "shipping_address": { - "confidence": 0.0, - "value": null - }, - "purchase_order": { - "confidence": 0.0, - "value": null - }, - "invoice_id": { - "confidence": 0.963, - "value": "IATIEN1819013536" - }, - "invoice_date": { - "confidence": 1.0, - "value": "2019-02-15" - }, - "payable_by": { - "confidence": 0.0, - "value": null - }, - "vendor_name": { - "confidence": 0.985, - "value": "ADISHAKTI CARS PVT. LTD." - }, - "vendor_address": { - "street": { - "confidence": 0.889, - "value": "#56, OPP. LUMBINI GARDEN MAIN GATE, SERVICE RING ROAD, VEERANAPALYA MAIN ROAD" - }, - "city": { - "confidence": 0.679, - "value": "BENGALURU" - }, - "state": { - "confidence": 0.965, - "value": "Karnataka" - }, - "postal_code": { - "confidence": 0.889, - "value": "560045" - }, - "country": { - "confidence": 0.953, - "value": "India" - } - }, - "vendor_tax_id": { - "confidence": 0.992, - "value": "29AAHCS6672E1ZZ" - }, - "remittance_address": { - "confidence": 0.0, - "value": null - }, - "subtotal": { - "confidence": 0.807, - "value": 350.0 - }, - "total_discount": { - "confidence": 0.938, - "value": 0.0 - }, - "total_tax": { - "confidence": 0.995, - "value": 63.0 - }, - "invoice_total": { - "confidence": 0.995, - "value": 413.0 - }, - "payment_terms": { - "confidence": 0.0, - "value": null - }, - "items": [ - { - "product_code": { - "confidence": 0.995, - "value": "FREE2" - }, - "description": { - "confidence": 0.962, - "value": "SECOND FREE SERVICE" - }, - "quantity": { - "confidence": 0.989, - "value": 1 - }, - "tax": { - "confidence": 0.98, - "value": 0.0 - }, - "tax_rate": { - "confidence": 0.94, - "value": "9%" - }, - "unit_price": { - "confidence": 0.945, - "value": 500.0 - }, - "total": { - "confidence": 0.793, - "value": 0.0 - }, - "reason": { - "confidence": 0.0, - "value": null - } - }, - { - "product_code": { - "confidence": 0.995, - "value": "423030" - }, - "description": { - "confidence": 1.0, - "value": "BRAKE BLEEDING" - }, - "quantity": { - "confidence": 0.989, - "value": 1 - }, - "tax": { - "confidence": 1.0, - "value": 0.0 - }, - "tax_rate": { - "confidence": 0.943, - "value": "9%" - }, - "unit_price": { - "confidence": 0.999, - "value": 0.0 - }, - "total": { - "confidence": 1.0, - "value": 0.0 - }, - "reason": { - "confidence": 0.0, - "value": null - } - }, - { - "product_code": { - "confidence": 0.996, - "value": "183090" - }, - "description": { - "confidence": 0.998, - "value": "BREATHER REPLACEMENT" - }, - "quantity": { - "confidence": 0.989, - "value": 1 - }, - "tax": { - "confidence": 1.0, - "value": 0.0 - }, - "tax_rate": { - "confidence": 0.943, - "value": "9%" - }, - "unit_price": { - "confidence": 1.0, - "value": 0.0 - }, - "total": { - "confidence": 1.0, - "value": 0.0 - }, - "reason": { - "confidence": 0.0, - "value": null - } - }, - { - "product_code": { - "confidence": 0.999, - "value": "AKSPROPLUS" - }, - "description": { - "confidence": 0.999, - "value": "SERVICE PLUS - AUTOKROM" - }, - "quantity": { - "confidence": 0.989, - "value": 1 - }, - "tax": { - "confidence": 0.947, - "value": 63.0 - }, - "tax_rate": { - "confidence": 0.855, - "value": "9%" - }, - "unit_price": { - "confidence": 0.998, - "value": 350.0 - }, - "total": { - "confidence": 0.986, - "value": 413.0 - }, - "reason": { - "confidence": 0.0, - "value": null - } - } - ], - "total_item_quantity": { - "confidence": 0.0, - "value": 4.0 - }, - "items_customer_signature": { - "signatory": { - "confidence": 0.723, - "value": "ANIL DB" - }, - "is_signed": { - "confidence": 0.0, - "value": true - } - }, - "items_vendor_signature": { - "signatory": { - "confidence": 0.724, - "value": "Authorized signatory" - }, - "is_signed": { - "confidence": 0.0, - "value": true - } - }, - "returns": [], - "total_return_quantity": { - "confidence": 0.0, - "value": null - }, - "returns_customer_signature": { - "confidence": 0.0, - "value": null - }, - "returns_vendor_signature": { - "confidence": 0.0, - "value": null - }, - "total_evaluated_fields_count": 50, - "overall_confidence": 0.94, - "min_extracted_field_confidence": 0.679, - "min_extracted_field_confidence_field": [ - "customer_address.postal_code", - "vendor_address.city" - ], - "missed_fields": [ - "shipping_address", - "purchase_order", - "payable_by", - "remittance_address", - "payment_terms", - "items[0].reason", - "items[1].reason", - "items[2].reason", - "items[3].reason", - "total_item_quantity", - "items_customer_signature.is_signed", - "items_vendor_signature.is_signed", - "total_return_quantity", - "returns_customer_signature", - "returns_vendor_signature" - ], - "missed_fields_count": 15, - "overall_hit_rate": 49.7 - }, - "comparison_result": { - "items": [ - { - "Field": "customer_address_city", - "Extracted": "Bangalore", - "Confidence": "69.30%", - "IsAboveThreshold": false, - "Hited": true - }, - { - "Field": "customer_address_country", - "Extracted": "India", - "Confidence": "95.30%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "customer_address_postal_code", - "Extracted": "560001", - "Confidence": "67.90%", - "IsAboveThreshold": false, - "Hited": true - }, - { - "Field": "customer_address_state", - "Extracted": "Karnataka", - "Confidence": "99.20%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "customer_address_street", - "Extracted": "Workafella Business Centre 150/1, Infantry Road, Opp. Commissioner Office, Vasanth Nagar", - "Confidence": "99.30%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "customer_name", - "Extracted": "ALD AUTOMOTIVE P LTD.", - "Confidence": "98.80%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "customer_tax_id", - "Extracted": "29AAFCA0924K1ZN", - "Confidence": "98.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "invoice_date", - "Extracted": "2019-02-15", - "Confidence": "100.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "invoice_id", - "Extracted": "IATIEN1819013536", - "Confidence": "96.30%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "invoice_total", - "Extracted": 413.0, - "Confidence": "99.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_0_description", - "Extracted": "SECOND FREE SERVICE", - "Confidence": "96.20%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_0_product_code", - "Extracted": "FREE2", - "Confidence": "99.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_0_quantity", - "Extracted": 1, - "Confidence": "98.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_0_reason", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "items_0_tax", - "Extracted": 0.0, - "Confidence": "98.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_0_tax_rate", - "Extracted": "9%", - "Confidence": "94.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_0_total", - "Extracted": 0.0, - "Confidence": "79.30%", - "IsAboveThreshold": false, - "Hited": true - }, - { - "Field": "items_0_unit_price", - "Extracted": 500.0, - "Confidence": "94.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_1_description", - "Extracted": "BRAKE BLEEDING", - "Confidence": "100.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_1_product_code", - "Extracted": "423030", - "Confidence": "99.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_1_quantity", - "Extracted": 1, - "Confidence": "98.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_1_reason", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "items_1_tax", - "Extracted": 0.0, - "Confidence": "100.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_1_tax_rate", - "Extracted": "9%", - "Confidence": "94.30%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_1_total", - "Extracted": 0.0, - "Confidence": "100.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_1_unit_price", - "Extracted": 0.0, - "Confidence": "99.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_2_description", - "Extracted": "BREATHER REPLACEMENT", - "Confidence": "99.80%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_2_product_code", - "Extracted": "183090", - "Confidence": "99.60%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_2_quantity", - "Extracted": 1, - "Confidence": "98.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_2_reason", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "items_2_tax", - "Extracted": 0.0, - "Confidence": "100.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_2_tax_rate", - "Extracted": "9%", - "Confidence": "94.30%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_2_total", - "Extracted": 0.0, - "Confidence": "100.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_2_unit_price", - "Extracted": 0.0, - "Confidence": "100.00%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_3_description", - "Extracted": "SERVICE PLUS - AUTOKROM", - "Confidence": "99.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_3_product_code", - "Extracted": "AKSPROPLUS", - "Confidence": "99.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_3_quantity", - "Extracted": 1, - "Confidence": "98.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_3_reason", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "items_3_tax", - "Extracted": 63.0, - "Confidence": "94.70%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_3_tax_rate", - "Extracted": "9%", - "Confidence": "85.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_3_total", - "Extracted": 413.0, - "Confidence": "98.60%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_3_unit_price", - "Extracted": 350.0, - "Confidence": "99.80%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "items_customer_signature_is_signed", - "Extracted": true, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "items_customer_signature_signatory", - "Extracted": "ANIL DB", - "Confidence": "72.30%", - "IsAboveThreshold": false, - "Hited": true - }, - { - "Field": "items_vendor_signature_is_signed", - "Extracted": true, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "items_vendor_signature_signatory", - "Extracted": "Authorized signatory", - "Confidence": "72.40%", - "IsAboveThreshold": false, - "Hited": true - }, - { - "Field": "payable_by", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "payment_terms", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "purchase_order", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "remittance_address", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "returns_customer_signature", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "returns_vendor_signature", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "shipping_address", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "subtotal", - "Extracted": 350.0, - "Confidence": "80.70%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "total_discount", - "Extracted": 0.0, - "Confidence": "93.80%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "total_item_quantity", - "Extracted": 4.0, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "total_return_quantity", - "Extracted": null, - "Confidence": "0.00%", - "IsAboveThreshold": false, - "Hited": false - }, - { - "Field": "total_tax", - "Extracted": 63.0, - "Confidence": "99.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "vendor_address_city", - "Extracted": "BENGALURU", - "Confidence": "67.90%", - "IsAboveThreshold": false, - "Hited": true - }, - { - "Field": "vendor_address_country", - "Extracted": "India", - "Confidence": "95.30%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "vendor_address_postal_code", - "Extracted": "560045", - "Confidence": "88.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "vendor_address_state", - "Extracted": "Karnataka", - "Confidence": "96.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "vendor_address_street", - "Extracted": "#56, OPP. LUMBINI GARDEN MAIN GATE, SERVICE RING ROAD, VEERANAPALYA MAIN ROAD", - "Confidence": "88.90%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "vendor_name", - "Extracted": "ADISHAKTI CARS PVT. LTD.", - "Confidence": "98.50%", - "IsAboveThreshold": true, - "Hited": true - }, - { - "Field": "vendor_tax_id", - "Extracted": "29AAHCS6672E1ZZ", - "Confidence": "99.20%", - "IsAboveThreshold": true, - "Hited": true - } - ] - }, - "prompt_tokens": 5865, - "completion_tokens": 491, - "execution_time": 0 -} \ No newline at end of file diff --git a/src/ContentProcessorWeb/src/Hooks/useAppHooks.tsx b/src/ContentProcessorWeb/src/Hooks/useAppHooks.tsx deleted file mode 100644 index 185b8af2..00000000 --- a/src/ContentProcessorWeb/src/Hooks/useAppHooks.tsx +++ /dev/null @@ -1,86 +0,0 @@ -// useAppHandlers.tsx -import { useState, useEffect } from "react"; - -export const useAppHooks = () => { - // State for Left Panel - const [isPanelOpen, setIsPanelOpen] = useState(true); - const [panelWidth, setPanelWidth] = useState(260); - const [isResizingLeft, setIsResizingLeft] = useState(false); - - // State for Right Panel - const [isRightPanelOpen, setIsRightPanelOpen] = useState(true); - const [rightPanelWidth, setRightPanelWidth] = useState(500); - const [isResizingRight, setIsResizingRight] = useState(false); - - // Left Panel Toggle - const togglePanel = () => setIsPanelOpen(!isPanelOpen); - - // Right Panel Toggle - const toggleRightPanel = () => setIsRightPanelOpen(!isRightPanelOpen); - - // Left Panel Resize Handlers - const handleMouseDownLeft = (e: React.MouseEvent) => { - setIsResizingLeft(true); - e.preventDefault(); - }; - - const handleMouseMoveLeft = (e: MouseEvent) => { - if (isResizingLeft) { - const newWidth = Math.min(Math.max(e.clientX, 192), 400); - setPanelWidth(newWidth); - } - }; - - const handleMouseUpLeft = () => setIsResizingLeft(false); - - // Right Panel Resize Handlers - const handleMouseDownRight = (e: React.MouseEvent) => { - setIsResizingRight(true); - e.preventDefault(); - }; - - const handleMouseMoveRight = (e: MouseEvent) => { - if (isResizingRight) { - const newWidth = Math.min( - Math.max(window.innerWidth - e.clientX, 260), - 500 - ); - setRightPanelWidth(newWidth); - } - }; - - const handleMouseUpRight = () => setIsResizingRight(false); - - useEffect(() => { - if (isResizingLeft) { - window.addEventListener("mousemove", handleMouseMoveLeft); - window.addEventListener("mouseup", handleMouseUpLeft); - } else if (isResizingRight) { - window.addEventListener("mousemove", handleMouseMoveRight); - window.addEventListener("mouseup", handleMouseUpRight); - } else { - window.removeEventListener("mousemove", handleMouseMoveLeft); - window.removeEventListener("mouseup", handleMouseUpLeft); - window.removeEventListener("mousemove", handleMouseMoveRight); - window.removeEventListener("mouseup", handleMouseUpRight); - } - - return () => { - window.removeEventListener("mousemove", handleMouseMoveLeft); - window.removeEventListener("mouseup", handleMouseUpLeft); - window.removeEventListener("mousemove", handleMouseMoveRight); - window.removeEventListener("mouseup", handleMouseUpRight); - }; - }, [isResizingLeft, isResizingRight]); - - return { - isPanelOpen, - panelWidth, - togglePanel, - handleMouseDownLeft, - isRightPanelOpen, - rightPanelWidth, - toggleRightPanel, - handleMouseDownRight, - }; -}; diff --git a/src/ContentProcessorWeb/src/Hooks/useContentHooks.tsx b/src/ContentProcessorWeb/src/Hooks/useContentHooks.tsx deleted file mode 100644 index a7e60042..00000000 --- a/src/ContentProcessorWeb/src/Hooks/useContentHooks.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { useEffect } from "react"; - -interface ContentHooksProps { - togglePanel?: () => void; // Optional for layouts without left panel - toggleRightPanel?: () => void; // Optional for layouts without right panel -} - -export const useContentHooks = ({ - togglePanel, - toggleRightPanel, -}: ContentHooksProps) => { - const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.platform); - const commandKey = isMac ? "⌘ + Shift" : "Ctrl + Shift"; - - useEffect(() => { - const handleKeydown = (event: KeyboardEvent) => { - // Check for Ctrl (or Command on Mac) + Shift + Arrow Keys - if ((event.ctrlKey || (isMac && event.metaKey)) && event.shiftKey) { - if (event.key === "ArrowLeft" && togglePanel) { - // Call togglePanel only if it exists - event.preventDefault(); // Prevent browser's default action - togglePanel(); - } else if (event.key === "ArrowRight" && toggleRightPanel) { - // Call toggleRightPanel only if it exists - event.preventDefault(); // Prevent browser's default action - toggleRightPanel(); - } - } - }; - - window.addEventListener("keydown", handleKeydown, { passive: false }); // Use non-passive listener - return () => { - window.removeEventListener("keydown", handleKeydown); - }; - }, [togglePanel, toggleRightPanel, isMac]); - - return { commandKey }; -}; diff --git a/src/ContentProcessorWeb/src/Hooks/useContentToolbarHooks.tsx b/src/ContentProcessorWeb/src/Hooks/useContentToolbarHooks.tsx deleted file mode 100644 index 125b2b95..00000000 --- a/src/ContentProcessorWeb/src/Hooks/useContentToolbarHooks.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React from "react"; -import "../Styles/App.css"; -import { Button, Tooltip, Toolbar, ToolbarDivider } from "@fluentui/react-components"; -import { - PanelLeftContract, - PanelLeftExpand, - PanelRightContract, - PanelRightExpand, -} from "../Imports/bundleIcons.tsx"; - -interface ContentToolbarProps { - isPanelOpen: boolean; - togglePanel?: () => void; - isRightPanelOpen: boolean; - toggleRightPanel?: () => void; - commandKey?: string; // Optional for shortcut hints - children?: React.ReactNode; // All nested components - panelConfig?: "left" | "right" | "both"; // Control which panel buttons to show -} - -const ContentToolbar: React.FC = ({ - isPanelOpen, - togglePanel, - isRightPanelOpen, - toggleRightPanel, - commandKey = "Ctrl", - children, - panelConfig = "both", // Default is to show both -}) => { - // Separate the first and the rest - const [firstToolbar, ...rest] = React.Children.toArray(children).filter( - (child) => React.isValidElement(child) && child.type === Toolbar - ); - - // Check if the first Toolbar has valid children - const firstToolbarHasChildren = React.isValidElement(firstToolbar) && - React.Children.toArray(firstToolbar.props.children).length > 0; - - // Check if any of the rest of the Toolbars have valid children - const restHasChildren = rest.some( - (child) => React.isValidElement(child) && - React.Children.toArray(child.props.children).length > 0 - ); - - return ( -
-
- {/* Show Left Panel Toggle and Divider if panelConfig is 'left' or 'both' */} - {togglePanel && (panelConfig === "left" || panelConfig === "both") && ( - <> - -
- -
- {rest} - {/* Show Divider and Right Panel Toggle if panelConfig is 'right' or 'both' */} - {toggleRightPanel && (panelConfig === "right" || panelConfig === "both") && ( - <> - {restHasChildren && ( - - )} - -
-
- ); -}; - -export default ContentToolbar; diff --git a/src/ContentProcessorWeb/src/Hooks/useSwaggerPreview.ts b/src/ContentProcessorWeb/src/Hooks/useSwaggerPreview.ts new file mode 100644 index 00000000..6a034ec0 --- /dev/null +++ b/src/ContentProcessorWeb/src/Hooks/useSwaggerPreview.ts @@ -0,0 +1,56 @@ +// src/hooks/useSwaggerPreview.ts +import { toast } from 'react-toastify'; + +const useSwaggerPreview = () => { + const openSwaggerUI = (swaggerJSON: object | null, apiUrl: string, token?: string) => { + if (!swaggerJSON) { + toast.error('Swagger JSON is missing!'); + return; + } + + // Clone the Swagger JSON to avoid mutation + const swaggerSpec = structuredClone(swaggerJSON) as any; + swaggerSpec.servers = [{ url: apiUrl, description: 'API Endpoint' }]; + + const newWindow = window.open('', '_blank'); + if (!newWindow) return; + + const htmlContent = ` + + + + Swagger UI + + + +
+ + + + + `; + + newWindow.document.write(htmlContent); + newWindow.document.close(); + }; + + return { openSwaggerUI }; +}; + +export default useSwaggerPreview; diff --git a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/CustomCellRender.tsx b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/CustomCellRender.tsx index 794d8c3e..841c58b7 100644 --- a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/CustomCellRender.tsx +++ b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/CustomCellRender.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { CaretUp16Filled, CaretDown16Filled, EditPersonFilled } from '@fluentui/react-icons'; import { Button, Menu, MenuTrigger, MenuPopover, MenuList, MenuItem } from '@fluentui/react-components'; -import { MoreVerticalRegular, MoreVerticalFilled, bundleIcon } from '@fluentui/react-icons'; +import { MoreVerticalRegular, MoreVerticalFilled, bundleIcon , Delete20Filled , Delete20Regular} from '@fluentui/react-icons'; type CellRendererProps = { type: string; @@ -13,6 +13,11 @@ const MoreVerticallIcon = bundleIcon( MoreVerticalRegular ); +const DeleteIcon = bundleIcon( + Delete20Filled, + Delete20Regular +); + const CellRenderer: React.FC = ({ type, props }) => { // Destructure props based on type const { @@ -51,21 +56,16 @@ const CellRenderer: React.FC = ({ type, props }) => { } const wholeValue = Math.round(decimalValue * 100); - let color; let numberClass = ''; // Apply color based on value if (wholeValue > 80) { - color = '#359B35'; numberClass = 'gClass'; } else if (wholeValue >= 50 && wholeValue <= 80) { - color = '#C19C00'; numberClass = 'yClass'; } else if (wholeValue >= 30 && wholeValue < 50) { - color = '#FF5F3DE5'; numberClass = 'oClass'; } else { - color = '#B10E1C'; numberClass = 'rClass'; } @@ -86,8 +86,9 @@ const CellRenderer: React.FC = ({ type, props }) => { if (lastModifiedBy === 'user') { return (
+ - Verified + Verified
); @@ -122,6 +123,7 @@ const CellRenderer: React.FC = ({ type, props }) => { } onClick={() => { setSelectedDeleteItem(item); toggleDialog(); diff --git a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.styles.scss b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.styles.scss index d965cad7..14b02376 100644 --- a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.styles.scss +++ b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.styles.scss @@ -1,117 +1,132 @@ -.col1 { - min-width: 120px !important; -} - -.col2 { - min-width: 55px !important; - max-width: 85px !important; -} - -.col3 { - min-width: 45px !important; - max-width: 70px !important; -} - -.col4 { - min-width: 35px !important; - max-width: 85px !important; -} - -.col5 { - min-width: 35px !important; - max-width: 85px !important; -} - -.col6 { - min-width: 45px !important; - max-width: 85px !important; -} - -.col7 { - min-width: 30px !important; - max-width: 35px !important; - box-sizing: border-box; -} - -.roundedBtn { - border: 1px solid #BDBDBD; - border-radius: 20px; - text-align: center; - padding: 1px 10px; - overflow: hidden; - text-overflow: ellipsis; - max-width: 75%; - white-space: nowrap; - font-size: 10px; - text-transform: capitalize; - - span { - color: #2C3C85 +.gridContainer { + height: 100vh; + + .gridTable { + min-width: 100%; + height: 100%; + display: flex; + flex-direction: column; + + .gridTableBody { + height: 100%; + } } - .ProcessedCls { - color: #00666D + .col1 { + min-width: 100px !important; } -} + .col2 { + min-width: 55px !important; + max-width: 85px !important; + } -.percentageContainer { - width: 100%; - text-align: center; + .col3 { + min-width: 45px !important; + max-width: 70px !important; + } - .gClass { - color: #359B35; + .col4 { + min-width: 35px !important; + max-width: 85px !important; } - .yClass { - color: #C19C00; + .col5 { + min-width: 35px !important; + max-width: 85px !important; } - .oClass { - color: #FF5F3DE5; + .col6 { + min-width: 55px !important; + max-width: 105px !important; + box-sizing: border-box; } - .rClass { - color: #B10E1C; + .col7 { + min-width: 30px !important; + max-width: 35px !important; + box-sizing: border-box; } - .textClass { - color: #0F6CBD + .roundedBtn { + border: 1px solid #BDBDBD; + border-radius: 20px; + text-align: center; + padding: 1px 10px; + overflow: hidden; + text-overflow: ellipsis; + max-width: 75%; + white-space: nowrap; + font-size: 10px; + text-transform: capitalize; + + span { + color: #2C3C85 + } + + .ProcessedCls { + color: #00666D + } + + } + + .percentageContainer { + width: 100%; + text-align: center; + + .gClass { + color: #359B35; + } + + .yClass { + color: #C19C00; + } + + .oClass { + color: #FF5F3DE5; + } + + .rClass { + color: #B10E1C; + } + + .textClass { + color: #0F6CBD + } } -} - -.GridList { - width: 100%; - // max-height: calc(100vh - 235px) !important; - // height: calc(100vh - 235px) !important; - flex: 1 1 auto; - height: 100%; - - //background-color: red; - >div { - width: 100% !important; + + .GridList { + width: 100%; + flex: 1 1 auto; + height: 100%; + + >div { + width: 100% !important; + } + } + + .columnCotainer { + font-size: 12px; + color: #323130; + width: 100%; + } + + .centerAlign { + text-align: center; + } + + .percentageContainer { + display: flex; + align-items: center; + justify-content: center; + flex-wrap: wrap; + } + + .editPersonIcon { + margin-right: 4px; + display: flex; + align-items: center; + justify-content: center; + color: #0F6CBD } -} - -.columnCotainer { - font-size: 12px; - color: #323130; - width: 100%; -} - -.centerAlign { - text-align: center; -} - -.percentageContainer { - display: flex; - align-items: center; - justify-content: center; -} - -.editPersonIcon { - margin-right: 4px; - display: flex; - align-items: center; - justify-content: center; } \ No newline at end of file diff --git a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.tsx b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.tsx index 2cf0c51a..a9ed6cfa 100644 --- a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.tsx +++ b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/ProcessQueueGrid/ProcessQueueGrid.tsx @@ -300,16 +300,22 @@ const ProcessQueueGrid: React.FC = () => { setIsDialogOpen(!isDialogOpen); }; + const dialogContnet = () => { + return ( +

Are you sure you want to delete this file?

+ ) + } + return ( <> -
+
@@ -323,7 +329,7 @@ const ProcessQueueGrid: React.FC = () => { {/*
*/} - +
{({ height, width }) => ( @@ -345,7 +351,7 @@ const ProcessQueueGrid: React.FC = () => { { + const status = ['extract', 'processing', 'map', 'evaluate']; + const [loadingStates, setLoadingStates] = useState({}); + const childRefs = useRef<{ [key: string]: HTMLDivElement | null }>({}); + + + const store = useSelector((state: RootState) => ({ + processStepsData: state.centerPanel.processStepsData, + selectedItem: state.leftPanel.selectedItem, + }), shallowEqual + ); + + const renderProcessTimeInSeconds = (timeString: string) => { + if (!timeString) { + return timeString; + } + const parts = timeString.split(":"); + if (parts.length !== 3) { + return timeString; + } + const [hours, minutes, seconds] = parts.map(Number); + const totalSeconds = (hours * 3600 + minutes * 60 + seconds).toFixed(2); + return `${totalSeconds}s`; + }; + + const handleExpand = (itemId: any) => { + setLoadingStates((prevState) => ({ ...prevState, [itemId]: true })); + setTimeout(() => { + const childDiv = childRefs.current[itemId]; + if (childDiv) { + childDiv.classList.add('loaded'); + } + }, 500); + + }; + + useEffect(() => { + const observers: MutationObserver[] = []; + Object.keys(childRefs.current).forEach((itemId) => { + const childDiv = childRefs.current[itemId]; + if (childDiv) { + const observer = new MutationObserver(() => { + if (childDiv.classList.contains('loaded')) { + setLoadingStates((prevState) => ({ ...prevState, [itemId]: false })); + } + }); + observer.observe(childDiv, { attributes: true, attributeFilter: ['class'] }); + observers.push(observer); + } + }); + return () => { + observers.forEach((observer) => observer.disconnect()); + }; + }, []); + + return ( + + {!status.includes(store.selectedItem.status) && store.processStepsData?.map((step, index) => ( + + handleExpand(index)}> {loadingStates[index] && } + {step.step_name} + + {renderProcessTimeInSeconds(step.processed_time)} + + +
(childRefs.current[index] = el)}> + + + +
+
+ ))} +
+ + ); +}; + +export default ProcessSteps; diff --git a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/SchemaDropdown/SchemaDropdown.tsx b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/SchemaDropdown/SchemaDropdown.tsx index 68e15226..3ba64164 100644 --- a/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/SchemaDropdown/SchemaDropdown.tsx +++ b/src/ContentProcessorWeb/src/Pages/DefaultPage/Components/SchemaDropdown/SchemaDropdown.tsx @@ -5,7 +5,7 @@ import './SchemaDropdown.styles.scss'; import { useDispatch, useSelector, shallowEqual } from 'react-redux'; import { RootState } from '../../../../store'; import { setSchemaSelectedOption } from '../../../../store/slices/leftPanelSlice'; -import { OptionList, SchemaItem, StoreState } from './SchemaDropdownTypes'; // Importing types +import { OptionList, SchemaItem, StoreState } from './SchemaDropdownTypes'; const useStyles = makeStyles({ root: { diff --git a/src/ContentProcessorWeb/src/Pages/DefaultPage/PanelCenter.tsx b/src/ContentProcessorWeb/src/Pages/DefaultPage/PanelCenter.tsx index 5cd861d1..5cc18d1a 100644 --- a/src/ContentProcessorWeb/src/Pages/DefaultPage/PanelCenter.tsx +++ b/src/ContentProcessorWeb/src/Pages/DefaultPage/PanelCenter.tsx @@ -1,39 +1,19 @@ -import React, { useCallback, useEffect,useState } from "react"; +import React, { useCallback, useEffect, useState } from "react"; import "../../Styles/App.css"; -import { - makeStyles, SelectTabData, SelectTabEvent, Tab, TabList, TabValue, Textarea, Divider, - Button, - Dialog, - DialogTitle, - DialogSurface, - DialogContent, - DialogActions, - Accordion, - AccordionItem, - AccordionHeader, - AccordionPanel -} from "@fluentui/react-components"; -import { useContentHooks } from "../../Hooks/useContentHooks.tsx"; +import { makeStyles, SelectTabData, SelectTabEvent, Tab, TabList, TabValue, Textarea, Divider, Button } from "@fluentui/react-components"; import { Field } from "@fluentui/react-components"; import PanelToolbar from "../../Hooks/usePanelHooks.tsx"; import JSONEditor from "../../Components/JSONEditor/JSONEditor" - import { useDispatch, useSelector, shallowEqual } from 'react-redux'; -import { saveContentJson, fetchProcessSteps ,setUpdateComments } from '../../store/slices/centerPanelSlice'; +import { saveContentJson, fetchProcessSteps, setUpdateComments } from '../../store/slices/centerPanelSlice'; import { RootState, AppDispatch } from '../../store'; import { startLoader, stopLoader } from "../../store/slices/loaderSlice.ts"; -import { createAsyncThunk } from "@reduxjs/toolkit"; -import httpUtility from "../../Services/httpUtility.ts"; -import { JsonEditor } from "json-edit-react"; -import { CheckmarkCircleFilled } from "@fluentui/react-icons"; -import { fetchContentJsonData , setActiveProcessId } from '../../store/slices/centerPanelSlice'; - +import { fetchContentJsonData, setActiveProcessId } from '../../store/slices/centerPanelSlice'; +import ProcessSteps from './Components/ProcessSteps/ProcessSteps'; +import { setRefreshGrid } from "../../store/slices/leftPanelSlice.ts"; -interface ContentProps { - isPanelOpen: boolean; - togglePanel?: () => void; // Optional to conditionally render left toggle - isRightPanelOpen: boolean; - toggleRightPanel?: () => void; // Optional to conditionally render left toggle +interface PanelCenterProps { + } const useStyles = makeStyles({ @@ -70,14 +50,18 @@ const useStyles = makeStyles({ height: 'calc(100vh - 383px)', border: '1px solid #DBDBDB', overflow: 'auto', - background: '#f6f6f6' + background: '#f6f6f6', + padding: '10px 5px', + boxSizing:'border-box' }, processTabItemCotnent: { height: 'calc(100vh - 200px)', border: '1px solid #DBDBDB', overflow: 'auto', - background: '#f6f6f6' + background: '#f6f6f6', + padding: '5px', + boxSizing:'border-box' }, fieldLabel: { fontWeight: 'bold', @@ -94,7 +78,7 @@ const useStyles = makeStyles({ saveButton: { marginTop: '10px', }, - apiLoader : { + apiLoader: { display: 'flex', justifyContent: 'center', alignItems: 'center', @@ -102,21 +86,14 @@ const useStyles = makeStyles({ } }) -const ContentDevelopers: React.FC = ({ - isPanelOpen, - togglePanel, - isRightPanelOpen, - toggleRightPanel, -}) => { - const { commandKey } = useContentHooks({ togglePanel, toggleRightPanel }); +const PanelCenter: React.FC = () => { const styles = useStyles(); const dispatch = useDispatch(); const [comment, setComment] = React.useState(""); - //const [selectedProcessId, setSelectedProcessId] = React.useState(null); const [selectedTab, setSelectedTab] = React.useState("extracted-results"); - const [ApiLoader ,setApiLoader] = useState(false); - const status = ['extract','processing','map','evaluate']; + const [ApiLoader, setApiLoader] = useState(false); + const status = ['extract', 'processing', 'map', 'evaluate']; const store = useSelector((state: RootState) => ({ processId: state.leftPanel.processId, @@ -125,13 +102,12 @@ const ContentDevelopers: React.FC = ({ modified_result: state.centerPanel.modified_result, isSavingInProgress: state.centerPanel.isSavingInProgress, processStepsData: state.centerPanel.processStepsData, - selectedItem : state.leftPanel.selectedItem, - activeProcessId : state.centerPanel.activeProcessId, + selectedItem: state.leftPanel.selectedItem, + activeProcessId: state.centerPanel.activeProcessId, }), shallowEqual ); useEffect(() => { - //setSelectedProcessId(store.processId); dispatch(setActiveProcessId(store.processId)) setComment(''); }, [store.processId]) @@ -142,39 +118,24 @@ const ContentDevelopers: React.FC = ({ useEffect(() => { - const fetchContent = async() =>{ + const fetchContent = async () => { try { setApiLoader(true); await Promise.allSettled([ - dispatch(fetchContentJsonData({ processId: store.activeProcessId })), - dispatch(fetchProcessSteps({ processId: store.activeProcessId })) - ]); + dispatch(fetchContentJsonData({ processId: store.activeProcessId })), + dispatch(fetchProcessSteps({ processId: store.activeProcessId })) + ]); } catch (error) { console.error("Error fetching data:", error); } finally { setApiLoader(false); } - } - if ((store.activeProcessId != null || store.activeProcessId != '') && !status.includes(store.selectedItem.status) && store.selectedItem?.process_id === store.activeProcessId ) { + } + if ((store.activeProcessId != null || store.activeProcessId != '') && !status.includes(store.selectedItem.status) && store.selectedItem?.process_id === store.activeProcessId) { fetchContent(); } }, [store.activeProcessId, store.selectedItem]) - const renderProcessTimeInSeconds = (timeString: string) => { - if (!timeString) { - return timeString; - } - - const parts = timeString.split(":"); - if (parts.length !== 3) { - return timeString; - } - - const [hours, minutes, seconds] = parts.map(Number); - const totalSeconds = (hours * 3600 + minutes * 60 + seconds).toFixed(2); - - return `${totalSeconds}s`; - }; const ExtractedResults = React.useCallback(() => (
@@ -182,45 +143,16 @@ const ContentDevelopers: React.FC = ({ - ) :

No data available

} + ) :

No data available

}
- ), [store.activeProcessId,store.selectedItem,store.contentData]); + ), [store.activeProcessId, store.selectedItem, store.contentData]); const ProcessHistory = useCallback(() => (
- - {!status.includes(store.selectedItem.status) && store.processStepsData?.map((step, index) => ( - - - {step.step_name} - - {renderProcessTimeInSeconds(step.processed_time)} - - - - - - - - ))} - - - {ApiLoader ?

Loading...

- : (store.processStepsData?.length == 0 || status.includes(store.selectedItem.status)) &&

No data available

} + {ApiLoader ?

Loading...

+ : (store.processStepsData?.length == 0 || status.includes(store.selectedItem.status)) ?

No data available

+ : + }
), [store.processStepsData, store.activeProcessId, styles.tabItemCotnent, ApiLoader]); @@ -232,19 +164,20 @@ const ContentDevelopers: React.FC = ({ try { dispatch(startLoader("1")); dispatch(setUpdateComments(comment)) - await dispatch(saveContentJson({ 'processId': store.activeProcessId, 'contentJson': store.modified_result.extracted_result, 'comments': comment , 'savedComments': store.comments })) + await dispatch(saveContentJson({ 'processId': store.activeProcessId, 'contentJson': store.modified_result.extracted_result, 'comments': comment, 'savedComments': store.comments })) } catch (error) { console.error('API Error:', error); } finally { + dispatch(setRefreshGrid(true)); dispatch(stopLoader("1")); } } const IsButtonSaveDisalbedCheck = () => { - if(status.includes(store.selectedItem.status)) return true; + if (status.includes(store.selectedItem.status)) return true; if (Object.keys(store.modified_result).length > 0) return false; if (comment.trim() !== store.comments && comment.trim() !== '') return false; - if (store.comments !=='' && comment.trim() === '') return false; + if (store.comments !== '' && comment.trim() === '') return false; return true; } @@ -253,9 +186,6 @@ const ContentDevelopers: React.FC = ({
- {/*
- -
*/} Extracted Results Process Steps @@ -274,8 +204,8 @@ const ContentDevelopers: React.FC = ({