mirror of
https://github.com/Qortal/chrome-extension.git
synced 2025-02-11 17:55:49 +00:00
fix navigation of app tabs
This commit is contained in:
parent
033de5816c
commit
1b44f26713
@ -2,6 +2,7 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
|
||||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Qortal Extension</title>
|
<title>Qortal Extension</title>
|
||||||
|
@ -57,3 +57,8 @@ export const hasSettingsChangedAtom = atom({
|
|||||||
key: 'hasSettingsChangedAtom',
|
key: 'hasSettingsChangedAtom',
|
||||||
default: false,
|
default: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const navigationControllerAtom = atom({
|
||||||
|
key: 'navigationControllerAtom',
|
||||||
|
default: {},
|
||||||
|
});
|
@ -1,25 +1,9 @@
|
|||||||
import React, { useContext, useEffect, useMemo, useRef, useState } from "react";
|
import React, { useContext, useEffect, useMemo, useState } from "react";
|
||||||
import {
|
|
||||||
AppCircle,
|
import { Avatar, Box, } from "@mui/material";
|
||||||
AppCircleContainer,
|
|
||||||
AppCircleLabel,
|
|
||||||
AppDownloadButton,
|
|
||||||
AppDownloadButtonText,
|
|
||||||
AppInfoAppName,
|
|
||||||
AppInfoSnippetContainer,
|
|
||||||
AppInfoSnippetLeft,
|
|
||||||
AppInfoSnippetMiddle,
|
|
||||||
AppInfoSnippetRight,
|
|
||||||
AppInfoUserName,
|
|
||||||
AppsLibraryContainer,
|
|
||||||
AppsParent,
|
|
||||||
} from "./Apps-styles";
|
|
||||||
import { Avatar, Box, ButtonBase, InputBase } from "@mui/material";
|
|
||||||
import { Add } from "@mui/icons-material";
|
import { Add } from "@mui/icons-material";
|
||||||
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
import { MyContext, getBaseApiReact, isMobile } from "../../App";
|
||||||
import LogoSelected from "../../assets/svgs/LogoSelected.svg";
|
|
||||||
|
|
||||||
import { Spacer } from "../../common/Spacer";
|
|
||||||
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
import { executeEvent, subscribeToEvent, unsubscribeFromEvent } from "../../utils/events";
|
||||||
import { useFrame } from "react-frame-component";
|
import { useFrame } from "react-frame-component";
|
||||||
import { useQortalMessageListener } from "./useQortalMessageListener";
|
import { useQortalMessageListener } from "./useQortalMessageListener";
|
||||||
@ -27,15 +11,16 @@ import { useQortalMessageListener } from "./useQortalMessageListener";
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const AppViewer = ({ app }) => {
|
export const AppViewer = React.forwardRef(({ app , hide}, iframeRef) => {
|
||||||
const { rootHeight } = useContext(MyContext);
|
const { rootHeight } = useContext(MyContext);
|
||||||
const iframeRef = useRef(null);
|
// const iframeRef = useRef(null);
|
||||||
const { document, window } = useFrame();
|
const { document, window: frameWindow } = useFrame();
|
||||||
const {path} = useQortalMessageListener(window)
|
const {path, history, changeCurrentIndex} = useQortalMessageListener(frameWindow, iframeRef, app?.tabId)
|
||||||
const [url, setUrl] = useState('')
|
const [url, setUrl] = useState('')
|
||||||
|
console.log('historyreact', history)
|
||||||
|
|
||||||
useEffect(()=> {
|
useEffect(()=> {
|
||||||
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${app?.path != null ? app?.path : ''}?theme=dark&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}`)
|
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${app?.path != null ? `/${app?.path}` : ''}?theme=dark&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}`)
|
||||||
}, [app?.service, app?.name, app?.identifier, app?.path])
|
}, [app?.service, app?.name, app?.identifier, app?.path])
|
||||||
const defaultUrl = useMemo(()=> {
|
const defaultUrl = useMemo(()=> {
|
||||||
return url
|
return url
|
||||||
@ -59,13 +44,106 @@ export const AppViewer = ({ app }) => {
|
|||||||
};
|
};
|
||||||
}, [app, path]);
|
}, [app, path]);
|
||||||
|
|
||||||
|
// Function to navigate back in iframe
|
||||||
|
const navigateBackInIframe = async () => {
|
||||||
|
if (iframeRef.current && iframeRef.current.contentWindow && history?.currentIndex > 0) {
|
||||||
|
// Calculate the previous index and path
|
||||||
|
const previousPageIndex = history.currentIndex - 1;
|
||||||
|
const previousPath = history.customQDNHistoryPaths[previousPageIndex];
|
||||||
|
|
||||||
|
// Signal non-manual navigation
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{ action: 'PERFORMING_NON_MANUAL' }, '*'
|
||||||
|
);
|
||||||
|
console.log('previousPageIndex', previousPageIndex)
|
||||||
|
// Update the current index locally
|
||||||
|
changeCurrentIndex(previousPageIndex);
|
||||||
|
|
||||||
|
// Create a navigation promise with a 200ms timeout
|
||||||
|
const navigationPromise = new Promise((resolve, reject) => {
|
||||||
|
function handleNavigationSuccess(event) {
|
||||||
|
console.log('listeninghandlenav', event)
|
||||||
|
if (event.data?.action === 'NAVIGATION_SUCCESS' && event.data.path === previousPath) {
|
||||||
|
frameWindow.removeEventListener('message', handleNavigationSuccess);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
frameWindow.addEventListener('message', handleNavigationSuccess);
|
||||||
|
|
||||||
|
// Timeout after 200ms if no response
|
||||||
|
setTimeout(() => {
|
||||||
|
window.removeEventListener('message', handleNavigationSuccess);
|
||||||
|
reject(new Error("Navigation timeout"));
|
||||||
|
}, 200);
|
||||||
|
|
||||||
|
// Send the navigation command after setting up the listener and timeout
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{ action: 'NAVIGATE_TO_PATH', path: previousPath, requestedHandler: 'UI' }, '*'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Execute navigation promise and handle timeout fallback
|
||||||
|
try {
|
||||||
|
await navigationPromise;
|
||||||
|
console.log('Navigation succeeded within 200ms.');
|
||||||
|
} catch (error) {
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{ action: 'PERFORMING_NON_MANUAL' }, '*'
|
||||||
|
);
|
||||||
|
setUrl(`${getBaseApiReact()}/render/${app?.service}/${app?.name}${app?.previousPath != null ? previousPath : ''}?theme=dark&identifier=${(app?.identifier != null && app?.identifier != 'null') ? app?.identifier : ''}&time=${new Date().getMilliseconds()}&isManualNavigation=false`)
|
||||||
|
// iframeRef.current.contentWindow.location.href = previousPath; // Fallback URL update
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Iframe not accessible or does not have a content window.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const navigateBackAppFunc = (e) => {
|
||||||
|
|
||||||
|
navigateBackInIframe()
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if(!app?.tabId) return
|
||||||
|
subscribeToEvent(`navigateBackApp-${app?.tabId}`, navigateBackAppFunc);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubscribeFromEvent(`navigateBackApp-${app?.tabId}`, navigateBackAppFunc);
|
||||||
|
};
|
||||||
|
}, [app, history]);
|
||||||
|
|
||||||
|
|
||||||
|
// Function to navigate back in iframe
|
||||||
|
const navigateForwardInIframe = async () => {
|
||||||
|
|
||||||
|
|
||||||
|
if (iframeRef.current && iframeRef.current.contentWindow) {
|
||||||
|
console.log('iframeRef.contentWindow', iframeRef.current.contentWindow);
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{ action: 'NAVIGATE_FORWARD'},
|
||||||
|
'*'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
console.log('Iframe not accessible or does not have a content window.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<iframe ref={iframeRef} style={{
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
}}>
|
||||||
|
|
||||||
|
<iframe ref={iframeRef} style={{
|
||||||
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`,
|
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
width: '100%'
|
width: '100%'
|
||||||
}} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" allow="fullscreen">
|
}} id="browser-iframe" src={defaultUrl} sandbox="allow-scripts allow-same-origin allow-forms allow-downloads allow-modals" allow="fullscreen">
|
||||||
|
|
||||||
</iframe>
|
</iframe>
|
||||||
|
</Box>
|
||||||
|
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
import React, { useContext, useEffect, useRef } from 'react'
|
import React, { useContext, } from 'react';
|
||||||
import { AppViewer } from './AppViewer'
|
import { AppViewer } from './AppViewer';
|
||||||
import Frame from 'react-frame-component';
|
import Frame from 'react-frame-component';
|
||||||
import { MyContext, isMobile } from '../../App';
|
import { MyContext, isMobile } from '../../App';
|
||||||
import { subscribeToEvent, unsubscribeFromEvent } from '../../utils/events';
|
|
||||||
|
|
||||||
const AppViewerContainer = ({app, isSelected, hide}) => {
|
|
||||||
const { rootHeight } = useContext(MyContext);
|
|
||||||
const frameRef = useRef(null);
|
|
||||||
|
|
||||||
|
const AppViewerContainer = React.forwardRef(({ app, isSelected, hide }, ref) => {
|
||||||
|
const { rootHeight } = useContext(MyContext);
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Frame id={`browser-iframe-${app?.tabId}` } ref={frameRef} head={
|
<Frame
|
||||||
|
id={`browser-iframe-${app?.tabId}`}
|
||||||
|
|
||||||
|
head={
|
||||||
<>
|
<>
|
||||||
{/* Inject styles directly into the iframe */}
|
|
||||||
<style>
|
<style>
|
||||||
{`
|
{`
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
/* Hide scrollbars for all elements */
|
|
||||||
* {
|
* {
|
||||||
-ms-overflow-style: none; /* IE and Edge */
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
scrollbar-width: none; /* Firefox */
|
scrollbar-width: none; /* Firefox */
|
||||||
@ -30,19 +28,23 @@ const AppViewerContainer = ({app, isSelected, hide}) => {
|
|||||||
}
|
}
|
||||||
.frame-content {
|
.frame-content {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: ${!isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`};
|
height: ${!isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px)`};
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
</style>
|
</style>
|
||||||
</>
|
</>
|
||||||
} style={{
|
}
|
||||||
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px )`,
|
style={{
|
||||||
border: 'none',
|
display: (!isSelected || hide) && 'none',
|
||||||
width: '100%',
|
height: !isMobile ? '100vh' : `calc(${rootHeight} - 60px - 45px)`,
|
||||||
overflow: 'hidden',
|
border: 'none',
|
||||||
display: (!isSelected || hide) && 'none'
|
width: '100%',
|
||||||
}} ><AppViewer app={app} /></Frame>
|
overflow: 'hidden',
|
||||||
)
|
}}
|
||||||
}
|
>
|
||||||
|
<AppViewer app={app} ref={ref} hide={!isSelected || hide} />
|
||||||
|
</Frame>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
export default AppViewerContainer
|
export default AppViewerContainer;
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { AppsHome } from "./AppsHome";
|
import { AppsHome } from "./AppsHome";
|
||||||
import { Spacer } from "../../common/Spacer";
|
import { Spacer } from "../../common/Spacer";
|
||||||
import { MyContext, getBaseApiReact } from "../../App";
|
import { getBaseApiReact } from "../../App";
|
||||||
import { AppInfo } from "./AppInfo";
|
import { AppInfo } from "./AppInfo";
|
||||||
import {
|
import {
|
||||||
executeEvent,
|
executeEvent,
|
||||||
subscribeToEvent,
|
subscribeToEvent,
|
||||||
unsubscribeFromEvent,
|
unsubscribeFromEvent,
|
||||||
} from "../../utils/events";
|
} from "../../utils/events";
|
||||||
import { AppsNavBar } from "./AppsNavBar";
|
|
||||||
import { AppsParent } from "./Apps-styles";
|
import { AppsParent } from "./Apps-styles";
|
||||||
import { AppViewer } from "./AppViewer";
|
|
||||||
import AppViewerContainer from "./AppViewerContainer";
|
import AppViewerContainer from "./AppViewerContainer";
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import { AppPublish } from "./AppPublish";
|
import { AppPublish } from "./AppPublish";
|
||||||
import { useRecoilState } from "recoil";
|
|
||||||
import { AppsCategory } from "./AppsCategory";
|
import { AppsCategory } from "./AppsCategory";
|
||||||
import { AppsLibrary } from "./AppsLibrary";
|
import { AppsLibrary } from "./AppsLibrary";
|
||||||
|
|
||||||
@ -28,6 +25,7 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
|||||||
const [selectedTab, setSelectedTab] = useState(null);
|
const [selectedTab, setSelectedTab] = useState(null);
|
||||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
||||||
const [categories, setCategories] = useState([])
|
const [categories, setCategories] = useState([])
|
||||||
|
const iframeRefs = useRef({});
|
||||||
|
|
||||||
|
|
||||||
const myApp = useMemo(()=> {
|
const myApp = useMemo(()=> {
|
||||||
@ -158,33 +156,26 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
|||||||
|
|
||||||
|
|
||||||
const navigateBackFunc = (e) => {
|
const navigateBackFunc = (e) => {
|
||||||
if(mode === 'category'){
|
if (['category', 'appInfo-from-category', 'appInfo', 'library', 'publish'].includes(mode)) {
|
||||||
setMode("library");
|
// Handle the various modes as needed
|
||||||
setSelectedCategory(null)
|
if (mode === 'category') {
|
||||||
} else if (mode === "appInfo-from-category") {
|
setMode('library');
|
||||||
setMode("category");
|
setSelectedCategory(null);
|
||||||
} else if (mode === "appInfo") {
|
} else if (mode === 'appInfo-from-category') {
|
||||||
setMode("library");
|
setMode('category');
|
||||||
} else if (mode === "library") {
|
} else if (mode === 'appInfo') {
|
||||||
if (isNewTabWindow) {
|
setMode('library');
|
||||||
setMode("viewer");
|
} else if (mode === 'library') {
|
||||||
} else {
|
if (isNewTabWindow) {
|
||||||
setMode("home");
|
setMode('viewer');
|
||||||
}
|
} else {
|
||||||
} else if(mode === 'publish'){
|
setMode('home');
|
||||||
setMode('library')
|
|
||||||
} else {
|
|
||||||
const iframeId = `browser-iframe-${selectedTab?.tabId}`;
|
|
||||||
const iframe = document.getElementById(iframeId);
|
|
||||||
// Go Back in the iframe's history
|
|
||||||
if (iframe) {
|
|
||||||
if (iframe && iframe.contentWindow) {
|
|
||||||
const iframeWindow = iframe.contentWindow;
|
|
||||||
if (iframeWindow && iframeWindow.history) {
|
|
||||||
iframeWindow.history.back();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (mode === 'publish') {
|
||||||
|
setMode('library');
|
||||||
}
|
}
|
||||||
|
} else if(selectedTab?.tabId) {
|
||||||
|
executeEvent(`navigateBackApp-${selectedTab?.tabId}`, {})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -309,11 +300,16 @@ export const Apps = ({ mode, setMode, show , myName}) => {
|
|||||||
{mode === "publish" && !selectedTab && <AppPublish names={myName ? [myName] : []} categories={categories} />}
|
{mode === "publish" && !selectedTab && <AppPublish names={myName ? [myName] : []} categories={categories} />}
|
||||||
|
|
||||||
{tabs.map((tab) => {
|
{tabs.map((tab) => {
|
||||||
|
if (!iframeRefs.current[tab.tabId]) {
|
||||||
|
iframeRefs.current[tab.tabId] = React.createRef();
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<AppViewerContainer
|
<AppViewerContainer
|
||||||
|
key={tab?.tabId}
|
||||||
hide={isNewTabWindow}
|
hide={isNewTabWindow}
|
||||||
isSelected={tab?.tabId === selectedTab?.tabId}
|
isSelected={tab?.tabId === selectedTab?.tabId}
|
||||||
app={tab}
|
app={tab}
|
||||||
|
ref={iframeRefs.current[tab.tabId]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -8,15 +8,10 @@ import {
|
|||||||
subscribeToEvent,
|
subscribeToEvent,
|
||||||
unsubscribeFromEvent,
|
unsubscribeFromEvent,
|
||||||
} from "../../utils/events";
|
} from "../../utils/events";
|
||||||
import { AppsNavBar } from "./AppsNavBar";
|
|
||||||
import { AppsParent } from "./Apps-styles";
|
import { AppsParent } from "./Apps-styles";
|
||||||
import { AppViewer } from "./AppViewer";
|
|
||||||
import AppViewerContainer from "./AppViewerContainer";
|
import AppViewerContainer from "./AppViewerContainer";
|
||||||
import ShortUniqueId from "short-unique-id";
|
import ShortUniqueId from "short-unique-id";
|
||||||
import { AppPublish } from "./AppPublish";
|
import { AppPublish } from "./AppPublish";
|
||||||
import { useRecoilState } from "recoil";
|
|
||||||
import { AppsCategory } from "./AppsCategory";
|
|
||||||
import { AppsLibrary } from "./AppsLibrary";
|
|
||||||
import { AppsLibraryDesktop } from "./AppsLibraryDesktop";
|
import { AppsLibraryDesktop } from "./AppsLibraryDesktop";
|
||||||
import { AppsCategoryDesktop } from "./AppsCategoryDesktop";
|
import { AppsCategoryDesktop } from "./AppsCategoryDesktop";
|
||||||
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
|
import { AppsNavBarDesktop } from "./AppsNavBarDesktop";
|
||||||
@ -36,8 +31,7 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
const [selectedTab, setSelectedTab] = useState(null);
|
const [selectedTab, setSelectedTab] = useState(null);
|
||||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
||||||
const [categories, setCategories] = useState([])
|
const [categories, setCategories] = useState([])
|
||||||
|
const iframeRefs = useRef({});
|
||||||
|
|
||||||
const myApp = useMemo(()=> {
|
const myApp = useMemo(()=> {
|
||||||
|
|
||||||
return availableQapps.find((app)=> app.name === myName && app.service === 'APP')
|
return availableQapps.find((app)=> app.name === myName && app.service === 'APP')
|
||||||
@ -165,37 +159,35 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const navigateBackFunc = (e) => {
|
const navigateBackFunc = (e) => {
|
||||||
if(mode === 'category'){
|
if (['category', 'appInfo-from-category', 'appInfo', 'library', 'publish'].includes(mode)) {
|
||||||
setMode("library");
|
// Handle the various modes as needed
|
||||||
setSelectedCategory(null)
|
if (mode === 'category') {
|
||||||
} else if (mode === "appInfo-from-category") {
|
setMode('library');
|
||||||
setMode("category");
|
setSelectedCategory(null);
|
||||||
} else if (mode === "appInfo") {
|
} else if (mode === 'appInfo-from-category') {
|
||||||
setMode("library");
|
setMode('category');
|
||||||
} else if (mode === "library") {
|
} else if (mode === 'appInfo') {
|
||||||
if (isNewTabWindow) {
|
setMode('library');
|
||||||
setMode("viewer");
|
} else if (mode === 'library') {
|
||||||
} else {
|
if (isNewTabWindow) {
|
||||||
setMode("home");
|
setMode('viewer');
|
||||||
}
|
} else {
|
||||||
} else if(mode === 'publish'){
|
setMode('home');
|
||||||
setMode('library')
|
|
||||||
} else {
|
|
||||||
const iframeId = `browser-iframe-${selectedTab?.tabId}`;
|
|
||||||
const iframe = document.getElementById(iframeId);
|
|
||||||
// Go Back in the iframe's history
|
|
||||||
if (iframe) {
|
|
||||||
if (iframe && iframe.contentWindow) {
|
|
||||||
const iframeWindow = iframe.contentWindow;
|
|
||||||
if (iframeWindow && iframeWindow.history) {
|
|
||||||
iframeWindow.history.back();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (mode === 'publish') {
|
||||||
|
setMode('library');
|
||||||
}
|
}
|
||||||
|
} else if(selectedTab?.tabId) {
|
||||||
|
executeEvent(`navigateBackApp-${selectedTab?.tabId}`, {})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent("navigateBack", navigateBackFunc);
|
subscribeToEvent("navigateBack", navigateBackFunc);
|
||||||
|
|
||||||
@ -217,6 +209,8 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
setIsNewTabWindow(false);
|
setIsNewTabWindow(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent("addTab", addTabFunc);
|
subscribeToEvent("addTab", addTabFunc);
|
||||||
|
|
||||||
@ -224,7 +218,6 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
unsubscribeFromEvent("addTab", addTabFunc);
|
unsubscribeFromEvent("addTab", addTabFunc);
|
||||||
};
|
};
|
||||||
}, [tabs]);
|
}, [tabs]);
|
||||||
|
|
||||||
const setSelectedTabFunc = (e) => {
|
const setSelectedTabFunc = (e) => {
|
||||||
const data = e.detail?.data;
|
const data = e.detail?.data;
|
||||||
|
|
||||||
@ -241,6 +234,7 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
setIsNewTabWindow(false);
|
setIsNewTabWindow(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
subscribeToEvent("setSelectedTab", setSelectedTabFunc);
|
subscribeToEvent("setSelectedTab", setSelectedTabFunc);
|
||||||
|
|
||||||
@ -364,7 +358,7 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
</ButtonBase>
|
</ButtonBase>
|
||||||
<Save isDesktop />
|
<Save isDesktop />
|
||||||
{mode !== 'home' && (
|
{mode !== 'home' && (
|
||||||
<AppsNavBarDesktop />
|
<AppsNavBarDesktop />
|
||||||
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -398,13 +392,17 @@ export const AppsDesktop = ({ mode, setMode, show , myName, goToHome, setDesktop
|
|||||||
{mode === "appInfo-from-category" && !selectedTab && <AppInfo app={selectedAppInfo} myName={myName} />}
|
{mode === "appInfo-from-category" && !selectedTab && <AppInfo app={selectedAppInfo} myName={myName} />}
|
||||||
<AppsCategoryDesktop availableQapps={availableQapps} isShow={mode === 'category' && !selectedTab} category={selectedCategory} myName={myName} />
|
<AppsCategoryDesktop availableQapps={availableQapps} isShow={mode === 'category' && !selectedTab} category={selectedCategory} myName={myName} />
|
||||||
{mode === "publish" && !selectedTab && <AppPublish names={myName ? [myName] : []} categories={categories} />}
|
{mode === "publish" && !selectedTab && <AppPublish names={myName ? [myName] : []} categories={categories} />}
|
||||||
|
|
||||||
{tabs.map((tab) => {
|
{tabs.map((tab) => {
|
||||||
|
if (!iframeRefs.current[tab.tabId]) {
|
||||||
|
iframeRefs.current[tab.tabId] = React.createRef();
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<AppViewerContainer
|
<AppViewerContainer
|
||||||
|
key={tab?.tabId}
|
||||||
hide={isNewTabWindow}
|
hide={isNewTabWindow}
|
||||||
isSelected={tab?.tabId === selectedTab?.tabId}
|
isSelected={tab?.tabId === selectedTab?.tabId}
|
||||||
app={tab}
|
app={tab}
|
||||||
|
ref={iframeRefs.current[tab.tabId]}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
AppsNavBarLeft,
|
AppsNavBarLeft,
|
||||||
AppsNavBarParent,
|
AppsNavBarParent,
|
||||||
@ -26,6 +26,7 @@ import PushPinIcon from "@mui/icons-material/PushPin";
|
|||||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||||
import { useRecoilState, useSetRecoilState } from "recoil";
|
import { useRecoilState, useSetRecoilState } from "recoil";
|
||||||
import {
|
import {
|
||||||
|
navigationControllerAtom,
|
||||||
settingsLocalLastUpdatedAtom,
|
settingsLocalLastUpdatedAtom,
|
||||||
sortablePinnedAppsAtom,
|
sortablePinnedAppsAtom,
|
||||||
} from "../../atoms/global";
|
} from "../../atoms/global";
|
||||||
@ -71,6 +72,13 @@ export const AppsNavBar = () => {
|
|||||||
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(
|
const [sortablePinnedApps, setSortablePinnedApps] = useRecoilState(
|
||||||
sortablePinnedAppsAtom
|
sortablePinnedAppsAtom
|
||||||
);
|
);
|
||||||
|
const [navigationController, setNavigationController] = useRecoilState(navigationControllerAtom)
|
||||||
|
|
||||||
|
const isDisableBackButton = useMemo(()=> {
|
||||||
|
if(selectedTab && navigationController[selectedTab?.tabId]?.hasBack) return false
|
||||||
|
if(selectedTab && !navigationController[selectedTab?.tabId]?.hasBack) return true
|
||||||
|
return false
|
||||||
|
}, [navigationController, selectedTab])
|
||||||
|
|
||||||
const setSettingsLocalLastUpdated = useSetRecoilState(
|
const setSettingsLocalLastUpdated = useSetRecoilState(
|
||||||
settingsLocalLastUpdatedAtom
|
settingsLocalLastUpdatedAtom
|
||||||
@ -103,7 +111,7 @@ export const AppsNavBar = () => {
|
|||||||
const { tabs, selectedTab, isNewTabWindow } = e.detail?.data;
|
const { tabs, selectedTab, isNewTabWindow } = e.detail?.data;
|
||||||
|
|
||||||
setTabs([...tabs]);
|
setTabs([...tabs]);
|
||||||
setSelectedTab(!selectedTab ? nulll : { ...selectedTab });
|
setSelectedTab(!selectedTab ? null : { ...selectedTab });
|
||||||
setIsNewTabWindow(isNewTabWindow);
|
setIsNewTabWindow(isNewTabWindow);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -123,8 +131,13 @@ export const AppsNavBar = () => {
|
|||||||
<AppsNavBarParent>
|
<AppsNavBarParent>
|
||||||
<AppsNavBarLeft>
|
<AppsNavBarLeft>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
executeEvent("navigateBack", {});
|
executeEvent("navigateBack", selectedTab?.tabId);
|
||||||
|
}}
|
||||||
|
disabled={isDisableBackButton}
|
||||||
|
sx={{
|
||||||
|
opacity: !isDisableBackButton ? 1 : 0.1,
|
||||||
|
cursor: !isDisableBackButton ? 'pointer': 'default'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img src={NavBack} />
|
<img src={NavBack} />
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import {
|
import {
|
||||||
AppsNavBarLeft,
|
AppsNavBarLeft,
|
||||||
AppsNavBarParent,
|
AppsNavBarParent,
|
||||||
@ -26,6 +26,7 @@ import PushPinIcon from "@mui/icons-material/PushPin";
|
|||||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||||
import { useRecoilState, useSetRecoilState } from "recoil";
|
import { useRecoilState, useSetRecoilState } from "recoil";
|
||||||
import {
|
import {
|
||||||
|
navigationControllerAtom,
|
||||||
settingsLocalLastUpdatedAtom,
|
settingsLocalLastUpdatedAtom,
|
||||||
sortablePinnedAppsAtom,
|
sortablePinnedAppsAtom,
|
||||||
} from "../../atoms/global";
|
} from "../../atoms/global";
|
||||||
@ -64,6 +65,8 @@ export function saveToLocalStorage(key, subKey, newValue) {
|
|||||||
export const AppsNavBarDesktop = () => {
|
export const AppsNavBarDesktop = () => {
|
||||||
const [tabs, setTabs] = useState([]);
|
const [tabs, setTabs] = useState([]);
|
||||||
const [selectedTab, setSelectedTab] = useState(null);
|
const [selectedTab, setSelectedTab] = useState(null);
|
||||||
|
const [navigationController, setNavigationController] = useRecoilState(navigationControllerAtom)
|
||||||
|
|
||||||
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
const [isNewTabWindow, setIsNewTabWindow] = useState(false);
|
||||||
const tabsRef = useRef(null);
|
const tabsRef = useRef(null);
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
@ -72,6 +75,7 @@ export const AppsNavBarDesktop = () => {
|
|||||||
sortablePinnedAppsAtom
|
sortablePinnedAppsAtom
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
const setSettingsLocalLastUpdated = useSetRecoilState(
|
const setSettingsLocalLastUpdated = useSetRecoilState(
|
||||||
settingsLocalLastUpdatedAtom
|
settingsLocalLastUpdatedAtom
|
||||||
);
|
);
|
||||||
@ -99,11 +103,22 @@ export const AppsNavBarDesktop = () => {
|
|||||||
}
|
}
|
||||||
}, [tabs.length]); // Dependency on the number of tabs
|
}, [tabs.length]); // Dependency on the number of tabs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const isDisableBackButton = useMemo(()=> {
|
||||||
|
if(selectedTab && navigationController[selectedTab?.tabId]?.hasBack) return false
|
||||||
|
if(selectedTab && !navigationController[selectedTab?.tabId]?.hasBack) return true
|
||||||
|
return false
|
||||||
|
}, [navigationController, selectedTab])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const setTabsToNav = (e) => {
|
const setTabsToNav = (e) => {
|
||||||
const { tabs, selectedTab, isNewTabWindow } = e.detail?.data;
|
const { tabs, selectedTab, isNewTabWindow } = e.detail?.data;
|
||||||
|
|
||||||
setTabs([...tabs]);
|
setTabs([...tabs]);
|
||||||
setSelectedTab(!selectedTab ? nulll : { ...selectedTab });
|
setSelectedTab(!selectedTab ? null : { ...selectedTab });
|
||||||
setIsNewTabWindow(isNewTabWindow);
|
setIsNewTabWindow(isNewTabWindow);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -115,6 +130,8 @@ export const AppsNavBarDesktop = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const isSelectedAppPinned = !!sortablePinnedApps?.find(
|
const isSelectedAppPinned = !!sortablePinnedApps?.find(
|
||||||
(item) =>
|
(item) =>
|
||||||
item?.name === selectedTab?.name && item?.service === selectedTab?.service
|
item?.name === selectedTab?.name && item?.service === selectedTab?.service
|
||||||
@ -138,7 +155,12 @@ export const AppsNavBarDesktop = () => {
|
|||||||
>
|
>
|
||||||
<ButtonBase
|
<ButtonBase
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
executeEvent("navigateBack", {});
|
executeEvent("navigateBack", selectedTab?.tabId);
|
||||||
|
}}
|
||||||
|
disabled={isDisableBackButton}
|
||||||
|
sx={{
|
||||||
|
opacity: !isDisableBackButton ? 1 : 0.1,
|
||||||
|
cursor: !isDisableBackButton ? 'pointer': 'default'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<img src={NavBack} />
|
<img src={NavBack} />
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
import { useEffect, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import FileSaver from 'file-saver';
|
import FileSaver from 'file-saver';
|
||||||
|
import { executeEvent } from '../../utils/events';
|
||||||
|
import { useSetRecoilState } from 'recoil';
|
||||||
|
import { navigationControllerAtom } from '../../atoms/global';
|
||||||
class Semaphore {
|
class Semaphore {
|
||||||
constructor(count) {
|
constructor(count) {
|
||||||
this.count = count
|
this.count = count
|
||||||
@ -313,13 +316,54 @@ const UIQortalRequests = [
|
|||||||
return obj; // Updated object with references to stored files
|
return obj; // Updated object with references to stored files
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useQortalMessageListener = (frameWindow) => {
|
export const useQortalMessageListener = (frameWindow, iframeRef, tabId) => {
|
||||||
const [path, setPath] = useState('')
|
const [path, setPath] = useState('')
|
||||||
|
const [history, setHistory] = useState({
|
||||||
|
customQDNHistoryPaths: [],
|
||||||
|
currentIndex: -1,
|
||||||
|
isDOMContentLoaded: false
|
||||||
|
})
|
||||||
|
const setHasSettingsChangedAtom = useSetRecoilState(navigationControllerAtom);
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(()=> {
|
||||||
|
if(tabId && !isNaN(history?.currentIndex)){
|
||||||
|
setHasSettingsChangedAtom((prev)=> {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[tabId]: {
|
||||||
|
hasBack: history?.currentIndex > 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [history?.currentIndex, tabId])
|
||||||
|
|
||||||
|
|
||||||
|
const changeCurrentIndex = useCallback((value)=> {
|
||||||
|
setHistory((prev)=> {
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
currentIndex: value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const resetHistory = useCallback(()=> {
|
||||||
|
setHistory({
|
||||||
|
customQDNHistoryPaths: [],
|
||||||
|
currentIndex: -1,
|
||||||
|
isManualNavigation: true,
|
||||||
|
isDOMContentLoaded: false
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
||||||
const listener = async (event) => {
|
const listener = async (event) => {
|
||||||
event.preventDefault(); // Prevent default behavior
|
console.log('eventreactt', event)
|
||||||
event.stopImmediatePropagation(); // Stop other listeners from firing
|
// event.preventDefault(); // Prevent default behavior
|
||||||
|
// event.stopImmediatePropagation(); // Stop other listeners from firing
|
||||||
|
|
||||||
if (event?.data?.requestedHandler !== 'UI') return;
|
if (event?.data?.requestedHandler !== 'UI') return;
|
||||||
|
|
||||||
@ -377,6 +421,39 @@ export const useQortalMessageListener = (frameWindow) => {
|
|||||||
event?.data?.action === 'QDN_RESOURCE_DISPLAYED'){
|
event?.data?.action === 'QDN_RESOURCE_DISPLAYED'){
|
||||||
const pathUrl = event?.data?.path != null ? (event?.data?.path.startsWith('/') ? '' : '/') + event?.data?.path : null
|
const pathUrl = event?.data?.path != null ? (event?.data?.path.startsWith('/') ? '' : '/') + event?.data?.path : null
|
||||||
setPath(pathUrl)
|
setPath(pathUrl)
|
||||||
|
} else if(event?.data?.action === 'NAVIGATION_HISTORY'){
|
||||||
|
if(event?.data?.payload?.isDOMContentLoaded){
|
||||||
|
setHistory((prev)=> {
|
||||||
|
const copyPrev = {...prev}
|
||||||
|
if((copyPrev?.customQDNHistoryPaths || []).at(-1) === (event?.data?.payload?.customQDNHistoryPaths || []).at(-1)) {
|
||||||
|
console.log('customQDNHistoryPaths.length', prev?.customQDNHistoryPaths.length)
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
currentIndex: prev.customQDNHistoryPaths.length - 1 === -1 ? 0 : prev.customQDNHistoryPaths.length - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const copyHistory = {...prev}
|
||||||
|
const paths = [...(copyHistory?.customQDNHistoryPaths || []), ...(event?.data?.payload?.customQDNHistoryPaths || [])]
|
||||||
|
console.log('paths', paths)
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
customQDNHistoryPaths: paths,
|
||||||
|
currentIndex: paths.length - 1
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setHistory(event?.data?.payload)
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if(event?.data?.action === 'SET_TAB'){
|
||||||
|
executeEvent("addTab", {
|
||||||
|
data: event?.data?.payload
|
||||||
|
})
|
||||||
|
iframeRef.current.contentWindow.postMessage(
|
||||||
|
{ action: 'SET_TAB_SUCCESS', requestedHandler: 'UI',payload: {
|
||||||
|
name: event?.data?.payload?.name
|
||||||
|
} }, '*'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -402,6 +479,6 @@ export const useQortalMessageListener = (frameWindow) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return {path}
|
return {path, history, resetHistory, changeCurrentIndex}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user