diff options
author | Sunil Shetye | 2025-03-28 12:57:32 +0530 |
---|---|---|
committer | Sunil Shetye | 2025-04-07 15:38:16 +0530 |
commit | 5180ed9cb4da5cb555aa8822abb681aea0d6a3d7 (patch) | |
tree | 4c14590a81392410cd8e3a75ad1df642be4c6d5e | |
parent | 08073c73fd18585a46266896c1e806aff05ca4ca (diff) | |
download | Common-Interface-Project-5180ed9cb4da5cb555aa8822abb681aea0d6a3d7.tar.gz Common-Interface-Project-5180ed9cb4da5cb555aa8822abb681aea0d6a3d7.tar.bz2 Common-Interface-Project-5180ed9cb4da5cb555aa8822abb681aea0d6a3d7.zip |
convert saveSchematic action/reducer to slice
13 files changed, 326 insertions, 378 deletions
diff --git a/blocks/eda-frontend/src/components/SchematicEditor/Header.js b/blocks/eda-frontend/src/components/SchematicEditor/Header.js index b40987aa..04c17d8a 100644 --- a/blocks/eda-frontend/src/components/SchematicEditor/Header.js +++ b/blocks/eda-frontend/src/components/SchematicEditor/Header.js @@ -30,7 +30,8 @@ import { makeStyles } from '@material-ui/core/styles' import { deepPurple } from '@material-ui/core/colors' import logo from '../../static/favicon.ico' -import { setTitle, setSchTitle, setSchShared } from '../../redux/actions/index' +import { setTitle } from '../../redux/actions/index' +import { setSchTitle, setSchShared } from '../../redux/saveSchematicSlice' import { logout } from '../../redux/authSlice' import { getDateTime as getDate, getUppercaseInitial } from '../../utils/GalleryUtils' @@ -104,10 +105,10 @@ function Header () { const classes = useStyles() const isAuthenticated = useSelector(state => state.auth.isAuthenticated) const user = useSelector(state => state.auth.user) - const details = useSelector(state => state.saveSchematicReducer.details) - const isSaved = useSelector(state => state.saveSchematicReducer.isSaved) - const isShared = useSelector(state => state.saveSchematicReducer.isShared) - const title = useSelector(state => state.saveSchematicReducer.title) + const details = useSelector(state => state.saveSchematic.details) + const isSaved = useSelector(state => state.saveSchematic.isSaved) + const isShared = useSelector(state => state.saveSchematic.isShared) + const title = useSelector(state => state.saveSchematic.title) const [anchorEl, setAnchorEl] = useState(null) const dispatch = useDispatch() diff --git a/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js b/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js index 71f14fad..c277950a 100644 --- a/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js +++ b/blocks/eda-frontend/src/components/SchematicEditor/Helper/ToolbarTools.js @@ -139,7 +139,7 @@ export function PrintPreview () { header.style.lineHeight = (this.marginTop - 10) + 'px' const footer = header.cloneNode(true) - const title = store.getState().saveSchematicReducer.title + const title = store.getState().saveSchematic.title mxUtils.write(header, title + ' - ' + process.env.REACT_APP_NAME + ' on Cloud') header.style.borderBottom = '1px solid blue' header.style.top = '0px' diff --git a/blocks/eda-frontend/src/components/SchematicEditor/PropertiesSidebar.js b/blocks/eda-frontend/src/components/SchematicEditor/PropertiesSidebar.js index baf6ed51..2752d38a 100644 --- a/blocks/eda-frontend/src/components/SchematicEditor/PropertiesSidebar.js +++ b/blocks/eda-frontend/src/components/SchematicEditor/PropertiesSidebar.js @@ -4,7 +4,7 @@ import { Hidden, List, ListItem, ListItemText, TextField, MenuItem, TextareaAuto import { makeStyles } from '@material-ui/core/styles' import ComponentProperties from './ComponentProperties' import { useSelector, useDispatch } from 'react-redux' -import { setSchDescription } from '../../redux/actions/index' +import { setSchDescription } from '../../redux/saveSchematicSlice' import './Helper/SchematicEditor.css' @@ -119,7 +119,7 @@ export default function PropertiesSidebar ({ gridRef, outlineRef }) { const classes = useStyles() const isOpen = useSelector(state => state.componentPropertiesReducer.isPropertiesWindowOpen) - const description1 = useSelector(state => state.saveSchematicReducer.description) + const description1 = useSelector(state => state.saveSchematic.description) const [description, setDescription] = useState(description1) diff --git a/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js b/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js index 1d36dd61..fabd47c3 100644 --- a/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js +++ b/blocks/eda-frontend/src/components/SchematicEditor/SchematicToolbar.js @@ -1,5 +1,5 @@ /* eslint new-cap: ["error", {"newIsCapExceptionPattern": "^mx"}] */ -import React, { useState } from 'react' +import React, { useEffect, useState } from 'react' import PropTypes from 'prop-types' import { Canvg } from 'canvg' import { @@ -31,9 +31,10 @@ import beautify from 'xml-beautifier' import mxGraphFactory from 'mxgraph' import { NetlistModal, HelpScreen, ImageExportDialog, OpenSchDialog, ScriptScreen } from './ToolbarExtension' -import { editorZoomIn, editorZoomOut, editorZoomAct, deleteComp, PrintPreview, Rotate, editorUndo, editorRedo, saveXml, ClearGrid } from './Helper/ToolbarTools' +import { editorZoomIn, editorZoomOut, editorZoomAct, deleteComp, PrintPreview, Rotate, editorUndo, editorRedo, saveXml, ClearGrid, renderGalleryXML } from './Helper/ToolbarTools' import { useSelector, useDispatch } from 'react-redux' -import { toggleSimulate, closeCompProperties, setSchXmlData, saveSchematic, openLocalSch, setLoadingDiagram } from '../../redux/actions/index' +import { toggleSimulate, closeCompProperties } from '../../redux/actions/index' +import { setSchXmlData, saveSchematic, openLocalSch, setLoadingDiagram } from '../../redux/saveSchematicSlice' import api from '../../utils/Api' import { transformXcos, saveToFile } from '../../utils/GalleryUtils' @@ -96,10 +97,11 @@ SimpleSnackbar.propTypes = { export default function SchematicToolbar ({ mobileClose, gridRef }) { const classes = useStyles() const isAuthenticated = useSelector(state => state.auth.isAuthenticated) - const description = useSelector(state => state.saveSchematicReducer.description) - const title2 = useSelector(state => state.saveSchematicReducer.title) + const description = useSelector(state => state.saveSchematic.description) + const xmlData = useSelector(state => state.saveSchematic.xmlData) + const title2 = useSelector(state => state.saveSchematic.title) - const scriptDump = useSelector(state => state.saveSchematicReducer.scriptDump) + const scriptDump = useSelector(state => state.saveSchematic.scriptDump) const dispatch = useDispatch() const isMobile = useMediaQuery('(max-width:600px)') @@ -158,6 +160,12 @@ export default function SchematicToolbar ({ mobileClose, gridRef }) { setSnacOpen(false) } + useEffect(() => { + if (xmlData) { + renderGalleryXML(xmlData) + } + }, [xmlData]) + // Image Export of Schematic Diagram async function exportImage (type) { try { @@ -296,7 +304,7 @@ export default function SchematicToolbar ({ mobileClose, gridRef }) { dispatch(setSchXmlData(xml)) exportImage('PNG') .then(res => { - dispatch(saveSchematic(title2, description, xml, res, scriptDump)) + dispatch(saveSchematic({ title: title2, description, xml, base64: res, scriptDump })) setMessage('Saved Successfully') }) .catch(err => { diff --git a/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js b/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js index b2fdb5ef..3e79ae4a 100644 --- a/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js +++ b/blocks/eda-frontend/src/components/SchematicEditor/ToolbarExtension.js @@ -36,11 +36,12 @@ import { import { makeStyles } from '@material-ui/core/styles' import CloseIcon from '@material-ui/icons/Close' import { useSelector, useDispatch } from 'react-redux' -import { fetchSchematic, fetchDiagram, setSchScriptDump } from '../../redux/actions/index' +import { fetchSchematic, fetchDiagram, setSchScriptDump } from '../../redux/saveSchematicSlice' import { fetchSchematics, fetchGallery } from '../../redux/dashboardSlice' import { setScriptTaskId } from '../../redux/simulationSlice' import { blue } from '@material-ui/core/colors' import { getDateTime as getDate, getUppercaseInitial, saveToFile } from '../../utils/GalleryUtils' +import { renderGalleryXML } from './Helper/ToolbarTools' import api from '../../utils/Api' const Transition = forwardRef(function Transition (props, ref) { @@ -338,7 +339,7 @@ HelpScreen.propTypes = { } export function ScriptScreen ({ isOpen, onClose }) { - const scriptDump = useSelector(state => state.saveSchematicReducer.scriptDump) + const scriptDump = useSelector(state => state.saveSchematic.scriptDump) const title = useSelector(state => state.netlistReducer.title) const dispatch = useDispatch() const scriptHandler = (e) => { @@ -522,11 +523,12 @@ export function OpenSchDialog (props) { const { open, close, openLocal } = props const [isLocal, setisLocal] = useState(true) const [isGallery, setisGallery] = useState(false) - const details = useSelector(state => state.saveSchematicReducer.details) + const details = useSelector(state => state.saveSchematic.details) const isAuthenticated = useSelector(state => state.auth.isAuthenticated) const user = useSelector(state => state.auth.user) const schematics = useSelector(state => state.dashboard.schematics) const GallerySchSample = useSelector(state => state.dashboard.gallery) + const xmlData = useSelector(state => state.schematicEditor.xmlData) const dispatch = useDispatch() @@ -534,6 +536,12 @@ export function OpenSchDialog (props) { dispatch(fetchGallery()) }, []) + useEffect(() => { + if (xmlData) { + renderGalleryXML(xmlData) + } + }, [xmlData]) + const title = 'Open ' + process.env.REACT_APP_DIAGRAM_NAME const typography1 = "You don't have any saved " + process.env.REACT_APP_SMALL_DIAGRAMS_NAME + '...' return ( diff --git a/blocks/eda-frontend/src/pages/SchematicEditor.js b/blocks/eda-frontend/src/pages/SchematicEditor.js index 61b078aa..72e39a6b 100644 --- a/blocks/eda-frontend/src/pages/SchematicEditor.js +++ b/blocks/eda-frontend/src/pages/SchematicEditor.js @@ -1,4 +1,4 @@ -// Main Layout for Schemaic Editor page. +// Main Layout for Schematic Editor page. import React, { useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import { TailSpin } from 'react-loader-spinner' @@ -13,8 +13,9 @@ import SchematicToolbar from '../components/SchematicEditor/SchematicToolbar' import RightSidebar from '../components/SchematicEditor/RightSidebar' import PropertiesSidebar from '../components/SchematicEditor/PropertiesSidebar' import LoadGrid from '../components/SchematicEditor/Helper/ComponentDrag' +import { renderGalleryXML } from '../components/SchematicEditor/Helper/ToolbarTools' import '../components/SchematicEditor/Helper/SchematicEditor.css' -import { fetchDiagram, fetchSchematic } from '../redux/actions/index' +import { fetchDiagram, fetchSchematic } from '../redux/saveSchematicSlice' import { useDispatch, useSelector } from 'react-redux' const useStyles = makeStyles((theme) => ({ @@ -34,13 +35,20 @@ export default function SchematicEditor (props) { const outlineRef = useRef() const dispatch = useDispatch() const [mobileOpen, setMobileOpen] = useState(false) - const isLoading = useSelector(state => state.saveSchematicReducer.isLoading) + const isLoading = useSelector(state => state.saveSchematic.isLoading) + const xmlData = useSelector(state => state.saveSchematic.xmlData) const handleDrawerToggle = () => { setMobileOpen(!mobileOpen) } useEffect(() => { + if (xmlData) { + renderGalleryXML(xmlData) + } + }, [xmlData]) + + useEffect(() => { document.title = process.env.REACT_APP_DIAGRAM_NAME + ' Editor - ' + process.env.REACT_APP_NAME const container = gridRef.current const sidebar = compRef.current @@ -52,11 +60,11 @@ export default function SchematicEditor (props) { const cktid = query.get('id') if (cktid.substring(0, 7) === 'gallery') { - // Loading Gallery schemaic. + // Loading Gallery schematic. dispatch(fetchDiagram(cktid)) } else { - // Loading User on-cloud saved schemaic. + // Loading User on-cloud saved schematic. dispatch(fetchSchematic(cktid)) } } diff --git a/blocks/eda-frontend/src/redux/actions/actions.js b/blocks/eda-frontend/src/redux/actions/actions.js index 87267226..56d69b00 100644 --- a/blocks/eda-frontend/src/redux/actions/actions.js +++ b/blocks/eda-frontend/src/redux/actions/actions.js @@ -16,18 +16,3 @@ export const CLOSE_COMP_PROPERTIES = 'CLOSE_COMP_PROPERTIES' export const SET_NETLIST = 'SET_NETLIST' export const SET_TITLE = 'SET_TITLE' export const SET_MODEL = 'SET_MODEL' - -// Actions for saving scheamtics and loading saved, gallery and local schematics. -export const LOADING_DIAGRAM = 'LOADING_DIAGRAM' -export const SAVE_SCHEMATICS = 'SAVE_SCHEMATICS' -export const SET_SCH_SAVED = 'SET_SCH_SAVED' -export const SET_SCH_TITLE = 'SET_SCH_TITLE' -export const SET_SCH_DESCRIPTION = 'SET_SCH_DESCRIPTION' -export const SET_SCH_XML_DATA = 'SET_SCH_XML_DATA' -export const SET_SCH_SHARED = 'SET_SCH_SHARED' -export const CLEAR_DETAILS = 'CLEAR_DETAILS' -export const LOAD_GALLERY = 'LOAD_GALLERY' -export const SET_SCH_SCRIPT_DUMP = 'SET_SCH_SCRIPT_DUMP' - -// Action for fetching on-cloud saved schematics for authenticated user to display in dashboard -export const FETCH_DIAGRAM = 'FETCH_DIAGRAM' diff --git a/blocks/eda-frontend/src/redux/actions/index.js b/blocks/eda-frontend/src/redux/actions/index.js index bd55df33..dcfac0f0 100644 --- a/blocks/eda-frontend/src/redux/actions/index.js +++ b/blocks/eda-frontend/src/redux/actions/index.js @@ -2,4 +2,3 @@ export * from './schematicEditorActions' export * from './componentPropertiesActions' export * from './netlistActions' -export * from './saveSchematicActions' diff --git a/blocks/eda-frontend/src/redux/actions/saveSchematicActions.js b/blocks/eda-frontend/src/redux/actions/saveSchematicActions.js deleted file mode 100644 index b4ae9466..00000000 --- a/blocks/eda-frontend/src/redux/actions/saveSchematicActions.js +++ /dev/null @@ -1,241 +0,0 @@ -import * as actions from './actions' -import queryString from 'query-string' -import api from '../../utils/Api' -import { renderGalleryXML } from '../../components/SchematicEditor/Helper/ToolbarTools' -import { setTitle } from './index' -import { transformXcos } from '../../utils/GalleryUtils' - -export const setLoadingDiagram = (isLoading) => (dispatch) => { - dispatch({ - type: actions.LOADING_DIAGRAM, - payload: { - isLoading - } - }) -} - -export const setSchTitle = (title) => (dispatch) => { - dispatch({ - type: actions.SET_SCH_TITLE, - payload: { - title - } - }) -} - -export const setSchDescription = (description) => (dispatch) => { - dispatch({ - type: actions.SET_SCH_DESCRIPTION, - payload: { - description - } - }) -} - -export const setSchXmlData = (xmlData) => (dispatch) => { - dispatch({ - type: actions.SET_SCH_XML_DATA, - payload: { - xmlData - } - }) -} - -export const setSchScriptDump = (scriptDump) => (dispatch) => { - dispatch({ - type: actions.SET_SCH_SCRIPT_DUMP, - payload: { - scriptDump - } - }) -} - -// Api call to save new schematic or updating saved schematic. -export const saveSchematic = (title, description, xml, base64, scriptDump) => (dispatch, getState) => { - const body = { - data_dump: xml, - base64_image: base64, - name: title, - description, - script_dump: scriptDump - } - - // Get token from localstorage - const token = getState().auth.token - const details = getState().saveSchematicReducer.details - const isSaved = getState().saveSchematicReducer.isSaved - - // add headers - const config = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } - } - - // If token available add to headers - if (token) { - config.headers.Authorization = `Token ${token}` - } - - if (isSaved) { - // Updating saved schemaic - api.post('save/diagram/' + details.save_id, queryString.stringify(body), config) - .then( - (res) => { - dispatch({ - type: actions.SET_SCH_SAVED, - payload: res.data - }) - } - ) - .catch((err) => { console.error(err) }) - } else { - // saving new schematic - api.post('save/diagram', queryString.stringify(body), config) - .then( - (res) => { - dispatch({ - type: actions.SET_SCH_SAVED, - payload: res.data - }) - } - ) - .catch((err) => { console.error(err) }) - } -} - -// Action for Loading on-cloud saved schematics -export const fetchSchematic = (saveId) => (dispatch, getState) => { - // Get token from localstorage - const token = getState().auth.token - - // add headers - const config = { - headers: { - 'Content-Type': 'application/x-www-form-urlencoded' - } - } - - // If token available add to headers - if (token) { - config.headers.Authorization = `Token ${token}` - } - - api.get('save/diagram/' + saveId, config) - .then( - (res) => { - dispatch({ - type: actions.SET_SCH_SAVED, - payload: res.data - }) - dispatch(setSchTitle(res.data.name)) - dispatch(setSchDescription(res.data.description)) - dispatch(setSchXmlData(res.data.data_dump)) - dispatch(setSchScriptDump(res.data.script_dump)) - renderGalleryXML(res.data.data_dump) - } - ) - .catch((err) => { console.error(err) }) -} - -export const fetchDiagram = (saveId) => (dispatch) => { - api.get('save/gallery/' + saveId) - .then( - (res) => { - dispatch(loadGallery(res.data)) - } - ) - .catch((err) => { console.error(err) }) -} - -export const setSchShared = (share) => (dispatch, getState) => { - // Get token from localstorage - const token = getState().auth.token - const details = getState().saveSchematicReducer.details - - // add headers - const config = { - headers: { - 'Content-Type': 'application/json' - } - } - - // If token available add to headers - if (token) { - config.headers.Authorization = `Token ${token}` - } - - let isShared - if (share === true) { - isShared = 'on' - } else { - isShared = 'off' - } - - api.post('save/' + details.save_id + '/sharing/' + isShared, {}, config) - .then( - (res) => { - dispatch({ - type: actions.SET_SCH_SHARED, - payload: res.data - }) - } - ) - .catch((err) => { console.error(err) }) -} - -// Action for Loading Gallery schematics -export const loadGallery = (data) => async (dispatch) => { - if (!data) { - console.error(`No gallery schematic found with save_id: ${data}`) - return - } - - dispatch(setLoadingDiagram(true)) - - try { - // Check if the data is xcos or xml - const parser = new DOMParser() - const xmlDoc = parser.parseFromString(data.data_dump, 'application/xml') - const isXcos = xmlDoc.getElementsByTagName('XcosDiagram').length > 0 - - const handleGalleryLoad = (data, dataDump) => { - dispatch({ - type: actions.LOAD_GALLERY, - payload: { ...data, data_dump: dataDump } - }) - dispatch(setTitle('* ' + data.name)) - dispatch(setSchTitle(data.name)) - dispatch(setSchDescription(data.description)) - dispatch(setSchXmlData(dataDump)) - dispatch(setSchScriptDump(data.script_dump)) - renderGalleryXML(dataDump) - } - - if (isXcos) { - const transformedXml = await transformXcos(xmlDoc) - const dataDump = new XMLSerializer().serializeToString(transformedXml) - handleGalleryLoad(data, dataDump) - } else { - handleGalleryLoad(data, data.data_dump) - } - } catch (error) { - console.error('Error loading gallery:', error) - } finally { - dispatch(setLoadingDiagram(false)) - window.loadGalleryComplete = true - } -} - -// Action for Loading local exported schematics -export const openLocalSch = (obj) => (dispatch) => { - const data = obj - - dispatch({ type: actions.CLEAR_DETAILS }) - dispatch(setTitle('* ' + data.title)) - dispatch(setSchTitle(data.title)) - dispatch(setSchDescription(data.description)) - dispatch(setSchXmlData(data.data_dump)) - dispatch(setSchScriptDump(data.script_dump)) - renderGalleryXML(data.data_dump) -} diff --git a/blocks/eda-frontend/src/redux/reducers/index.js b/blocks/eda-frontend/src/redux/reducers/index.js index e8474bb2..bb3fc882 100644 --- a/blocks/eda-frontend/src/redux/reducers/index.js +++ b/blocks/eda-frontend/src/redux/reducers/index.js @@ -2,10 +2,8 @@ import { combineReducers } from 'redux' import schematicEditorReducer from './schematicEditorReducer' import componentPropertiesReducer from './componentPropertiesReducer' import netlistReducer from './netlistReducer' -import saveSchematicReducer from './saveSchematicReducer' export default combineReducers({ schematicEditorReducer, componentPropertiesReducer, - netlistReducer, - saveSchematicReducer + netlistReducer }) diff --git a/blocks/eda-frontend/src/redux/reducers/saveSchematicReducer.js b/blocks/eda-frontend/src/redux/reducers/saveSchematicReducer.js deleted file mode 100644 index 3aa288f5..00000000 --- a/blocks/eda-frontend/src/redux/reducers/saveSchematicReducer.js +++ /dev/null @@ -1,95 +0,0 @@ -import * as actions from '../actions/actions' - -const initialState = { - title: 'Untitled', - description: '', - xmlData: null, - details: {}, - isLoading: false, - isSaved: null, - isShared: null -} - -export default function saveSchematicReducer (state = initialState, action) { - switch (action.type) { - case actions.LOADING_DIAGRAM: { - return { - ...state, - isLoading: action.payload.isLoading - } - } - - case actions.SET_SCH_SAVED: { - return { - ...state, - isSaved: true, - isShared: action.payload.shared, - details: action.payload - } - } - - case actions.SET_SCH_SHARED: { - return { - ...state, - isShared: true, - details: action.payload - } - } - - case actions.CLEAR_DETAILS: { - return { - ...state, - isSaved: null, - isShared: null, - details: {} - } - } - - case actions.LOAD_GALLERY: { - return { - ...state, - isSaved: null, - isShared: null, - details: action.payload - } - } - - case actions.FETCH_DIAGRAM: { - return { - ...state, - data: action.payload - } - } - - case actions.SET_SCH_TITLE: { - return { - ...state, - title: action.payload.title - } - } - - case actions.SET_SCH_DESCRIPTION: { - return { - ...state, - description: action.payload.description - } - } - - case actions.SET_SCH_XML_DATA: { - return { - ...state, - xmlData: action.payload.xmlData - } - } - - case actions.SET_SCH_SCRIPT_DUMP: { - return { - ...state, - scriptDump: action.payload.scriptDump - } - } - - default: - return state - } -} diff --git a/blocks/eda-frontend/src/redux/saveSchematicSlice.js b/blocks/eda-frontend/src/redux/saveSchematicSlice.js new file mode 100644 index 00000000..639e130b --- /dev/null +++ b/blocks/eda-frontend/src/redux/saveSchematicSlice.js @@ -0,0 +1,275 @@ +import { createSlice, createAsyncThunk } from '@reduxjs/toolkit' + +import api from '../utils/Api' +import { transformXcos } from '../utils/GalleryUtils' + +const initialState = { + title: 'Untitled', + description: '', + xmlData: null, + scriptDump: '', + details: {}, + isLoading: false, + isSaved: null, + isShared: null +} + +// Api call to save new schematic or updating saved schematic. +export const saveSchematic = createAsyncThunk( + 'saveSchematic/saveSchematic', + async ({ title, description, xml, base64, scriptDump }, { getState, rejectWithValue }) => { + // Get token from localstorage + const token = getState().auth.token + if (!token) return rejectWithValue('No token found') + const isSaved = getState().saveSchematic.isSaved + const details = getState().saveSchematic.details + + // add headers + const config = { + headers: { + 'Content-Type': 'application/json', + Authorization: `Token ${token}` + } + } + + const body = { + data_dump: xml, + base64_image: base64, + name: title, + description, + script_dump: scriptDump + } + + try { + const url = `save/diagram${isSaved ? `/${details.save_id}` : ''}` + const res = await api.post(url, body, config) + if (res.status === 200) { + return res.data + } + + return rejectWithValue(res.data || 'Failed to save schematic') + } catch (err) { + console.log(err) + const res = err.response + return rejectWithValue(res?.data || 'Failed to save schematic') + } + }) + +// Action for Loading on-cloud saved schematics +export const fetchSchematic = createAsyncThunk( + 'saveSchematic/fetchSchematic', + async (saveId, { getState, rejectWithValue }) => { + // Get token from localstorage + const token = getState().auth.token + if (!token) return rejectWithValue('No token found') + + // add headers + const config = { + headers: { + 'Content-Type': 'application/json', + Authorization: `Token ${token}` + } + } + + try { + const res = await api.get(`save/diagram/${saveId}`, config) + if (res.status === 200) { + return res.data + } + + return rejectWithValue(res.data || 'Failed to load schematic') + } catch (err) { + console.log(err) + const res = err.response + return rejectWithValue(res?.data || 'Failed to load schematic') + } + }) + +// Action for Loading on-cloud saved schematics +export const fetchDiagram = createAsyncThunk( + 'saveSchematic/fetchDiagram', + async (saveId, { rejectWithValue }) => { + try { + const res = await api.get(`save/gallery/${saveId}`) + if (res.status === 200) { + res.data.data_dump = await loadGallery(res.data)() + return res.data + } + + return rejectWithValue(res.data || 'Failed to load diagram') + } catch (err) { + console.log(err) + const res = err.response + return rejectWithValue(res?.data || 'Failed to load diagram') + } + }) + +export const setSchShared = createAsyncThunk( + 'saveSchematic/setSchShared', + async (share, { getState, rejectWithValue }) => { + // Get token from localstorage + const token = getState().auth.token + if (!token) return rejectWithValue('No token found') + + const details = getState().saveSchematic.details + + // add headers + const config = { + headers: { + 'Content-Type': 'application/json', + Authorization: `Token ${token}` + } + } + + const isShared = share ? 'on' : 'off' + + try { + const res = await api.get(`save/${details.save_id}/sharing/${isShared}`, config) + if (res.status === 200) { + return res.data + } + + return rejectWithValue(res.data || 'Failed to share schematic') + } catch (err) { + console.log(err) + const res = err.response + return rejectWithValue(res?.data || 'Failed to share schematic') + } + }) + +// Action for Loading local exported schematics +export const openLocalSch = createAsyncThunk( + 'saveSchematic/openLocalSch', + async (data) => { + return data + }) + +// Action for Loading Gallery diagrams +const loadGallery = (data) => async () => { + if (!data) { + console.error('No diagram found') + return + } + + try { + // Check if the data is xcos or xml + const parser = new DOMParser() + let dataDump = data.data_dump + const xmlDoc = parser.parseFromString(dataDump, 'application/xml') + const isXcos = xmlDoc.getElementsByTagName('XcosDiagram').length > 0 + if (isXcos) { + dataDump = new XMLSerializer().serializeToString(await transformXcos(xmlDoc)) + } + return dataDump + } catch (error) { + console.error('Error loading gallery:', error) + } finally { + window.loadGalleryComplete = true + } +} + +const saveSchematicSlice = createSlice({ + name: 'saveSchematic', + initialState, + reducers: { + setLoadingDiagram: (state, action) => { + state.isLoading = action.payload + }, + setSchTitle: (state, action) => { + state.title = action.payload + }, + setSchDescription: (state, action) => { + state.description = action.payload + }, + setSchXmlData: (state, action) => { + state.xmlData = action.payload + }, + setSchScriptDump: (state, action) => { + state.scriptDump = action.payload + } + }, + extraReducers: (builder) => { + builder + .addCase(saveSchematic.pending, (state) => { + state.isLoading = true + }) + .addCase(saveSchematic.fulfilled, (state, action) => { + state.isLoading = false + state.details = action.payload + state.isSaved = true + state.isShared = action.payload.shared + }) + .addCase(saveSchematic.rejected, (state) => { + state.isLoading = false + }) + .addCase(fetchSchematic.pending, (state) => { + state.isLoading = true + }) + .addCase(fetchSchematic.fulfilled, (state, action) => { + state.isLoading = false + state.details = action.payload + state.description = action.payload.description + state.isSaved = true + state.isShared = action.payload.shared + state.title = action.payload.name + state.xmlData = action.payload.data_dump + state.scriptDump = action.payload.script_dump + }) + .addCase(fetchSchematic.rejected, (state) => { + state.isLoading = false + }) + .addCase(fetchDiagram.pending, (state) => { + state.isLoading = true + }) + .addCase(fetchDiagram.fulfilled, (state, action) => { + state.isLoading = false + state.details = action.payload + state.description = action.payload.description + state.isSaved = false + state.isShared = false + state.title = action.payload.name + state.xmlData = action.payload.data_dump + state.scriptDump = action.payload.script_dump + }) + .addCase(fetchDiagram.rejected, (state) => { + state.isLoading = false + }) + .addCase(setSchShared.pending, (state) => { + state.isLoading = true + }) + .addCase(setSchShared.fulfilled, (state, action) => { + state.isLoading = false + state.details = action.payload + state.isShared = action.payload.shared + }) + .addCase(setSchShared.rejected, (state) => { + state.isLoading = false + }) + .addCase(openLocalSch.pending, (state) => { + state.isLoading = true + }) + .addCase(openLocalSch.fulfilled, (state, action) => { + state.isLoading = false + state.details = action.payload + state.description = action.payload.description + state.isSaved = true + state.isShared = action.payload.shared + state.title = action.payload.name + state.xmlData = action.payload.data_dump + state.scriptDump = action.payload.script_dump + }) + .addCase(openLocalSch.rejected, (state) => { + state.isLoading = false + }) + } +}) + +export const { + setLoadingDiagram, + setSchTitle, + setSchDescription, + setSchXmlData, + setSchScriptDump +} = saveSchematicSlice.actions + +export default saveSchematicSlice.reducer diff --git a/blocks/eda-frontend/src/redux/store.js b/blocks/eda-frontend/src/redux/store.js index 4e16a2a1..c504f79d 100644 --- a/blocks/eda-frontend/src/redux/store.js +++ b/blocks/eda-frontend/src/redux/store.js @@ -1,12 +1,14 @@ import { configureStore } from '@reduxjs/toolkit' import authReducer from './authSlice' import dashboardReducer from './dashboardSlice' +import saveSchematicReducer from './saveSchematicSlice' import simulationReducer from './simulationSlice' const store = configureStore({ reducer: { auth: authReducer, dashboard: dashboardReducer, + saveSchematic: saveSchematicReducer, simulation: simulationReducer }, middleware: (getDefaultMiddleware) => getDefaultMiddleware() |