diff --git a/react/src/components/MainLayout/MainLayout.tsx b/react/src/components/MainLayout/MainLayout.tsx index 3853d1f51d..c161e72b25 100644 --- a/react/src/components/MainLayout/MainLayout.tsx +++ b/react/src/components/MainLayout/MainLayout.tsx @@ -6,6 +6,7 @@ import BAIErrorBoundary from '../BAIErrorBoundary'; import BAISider from '../BAISider'; import Flex from '../Flex'; import ForceTOTPChecker from '../ForceTOTPChecker'; +import NetworkStatusBanner from '../NetworkStatusBanner'; import PasswordChangeRequestAlert from '../PasswordChangeRequestAlert'; import { DRAWER_WIDTH } from '../WEBUINotificationDrawer'; import WebUIHeader from './WebUIHeader'; @@ -169,6 +170,7 @@ function MainLayout() { zIndex: HEADER_Z_INDEX_IN_MAIN_LAYOUT, }} > + setSideCollapsed((v) => !v)} containerElement={contentScrollFlexRef.current} diff --git a/react/src/components/NetworkStatusBanner.tsx b/react/src/components/NetworkStatusBanner.tsx new file mode 100644 index 0000000000..99f7c8f0d0 --- /dev/null +++ b/react/src/components/NetworkStatusBanner.tsx @@ -0,0 +1,55 @@ +import { useNetwork } from 'ahooks'; +import { Alert } from 'antd'; +import { createStyles } from 'antd-style'; +import { atom, useAtom } from 'jotai'; +import { useTranslation } from 'react-i18next'; + +const networkSoftTimeoutAtom = atom(false); + +const useStyles = createStyles(({ token, css }) => ({ + borderError: css` + border-bottom: 1px solid ${token.colorErrorBorder} !important; + `, + borderWarning: css` + border-bottom: 1px solid ${token.colorWarningBorder} !important; + `, +})); +const NetworkStatusBanner = () => { + const { t } = useTranslation(); + const network = useNetwork(); + + const { styles } = useStyles(); + + const [softTimeout, setSoftTimeout] = useAtom(networkSoftTimeoutAtom); + + // const handler = (()=>{ + // }); + + // useEffect(()=>{ + // document.addEventListener('backendai.client.softtimeout', handler); + // return ()=>{ + // document.removeEventListener('backendai.client.softtimeout', handler); + // } + // },[]) + + return !network.online ? ( + + ) : softTimeout ? ( + { + setSoftTimeout(false); + }} + /> + ) : null; +}; + +export default NetworkStatusBanner; diff --git a/resources/i18n/de.json b/resources/i18n/de.json index afac50441d..8760552f97 100644 --- a/resources/i18n/de.json +++ b/resources/i18n/de.json @@ -68,7 +68,7 @@ "MyEnvironments": "Meine Umgebungen", "ResourcePolicy": "Ressourcenpolitik" }, - "YouAreOffline": "Du bist jetzt offline", + "YouAreOffline": "Offline: Keine Verbindung zu einem Netzwerk.", "YouAreOnline": "Sie sind jetzt online", "NOTFOUND": "

Hoppla!
Seite nicht gefunden...

", "DescNOTFOUND": "Die von Ihnen gesuchte Seite konnte leider nicht gefunden werden.", diff --git a/resources/i18n/el.json b/resources/i18n/el.json index 2f5180374f..9a1176e578 100644 --- a/resources/i18n/el.json +++ b/resources/i18n/el.json @@ -68,7 +68,7 @@ "MyEnvironments": "Τα περιβάλλοντα μου", "ResourcePolicy": "Πολιτική Πόρων" }, - "YouAreOffline": "Είστε πλέον εκτός σύνδεσης", + "YouAreOffline": "Offline: Δεν είναι συνδεδεμένος σε κανένα δίκτυο.", "YouAreOnline": "Είστε πλέον συνδεδεμένοι", "NOTFOUND": " α0d4554eb75c21z0 Ωχ!
Η σελίδα δεν βρέθηκε ...

", "DescNOTFOUND": "Δυστυχώς, δεν ήταν δυνατή η εύρεση της σελίδας που αναζητάτε.", diff --git a/resources/i18n/en.json b/resources/i18n/en.json index ab21c3852e..d7ac6323c0 100644 --- a/resources/i18n/en.json +++ b/resources/i18n/en.json @@ -68,7 +68,7 @@ "MyEnvironments": "My Environments", "ResourcePolicy": "Resource Policy" }, - "YouAreOffline": "You are now offline", + "YouAreOffline": "Offline: Not connected to any networks.", "YouAreOnline": "You are now online", "NOTFOUND": "

Oops!
Page not Found...

", "DescNOTFOUND": "Sorry, the page you are looking for could not be found.", diff --git a/resources/i18n/es.json b/resources/i18n/es.json index f4a1a9c2cd..1869de7e30 100644 --- a/resources/i18n/es.json +++ b/resources/i18n/es.json @@ -1505,7 +1505,7 @@ "DescNOTFOUND": "Lo sentimos, no se ha encontrado la página que busca.", "NOTFOUND": "

¡Oops!
Página no encontrada...

", "UNAUTHORIZEDACCESS": "Acceso no autorizado", - "YouAreOffline": "Ahora está desconectado", + "YouAreOffline": "Desconectado: No conectado a ninguna red.", "YouAreOnline": "Ya está en línea", "menu": { "AIAccelerator": "Acelerador de IA", diff --git a/resources/i18n/fi.json b/resources/i18n/fi.json index eccf96236c..4105812cc5 100644 --- a/resources/i18n/fi.json +++ b/resources/i18n/fi.json @@ -1503,7 +1503,7 @@ "DescNOTFOUND": "Valitettavasti etsimääsi sivua ei löytynyt.", "NOTFOUND": "

Oops!
Sivua ei löydy...

", "UNAUTHORIZEDACCESS": "Luvaton pääsy", - "YouAreOffline": "Olet nyt offline-tilassa", + "YouAreOffline": "Offline: Ei yhteyttä mihinkään verkkoon.", "YouAreOnline": "Olet nyt verkossa", "menu": { "AIAccelerator": "AI-kiihdyttämö", diff --git a/resources/i18n/fr.json b/resources/i18n/fr.json index fb53639fa8..33180b379b 100644 --- a/resources/i18n/fr.json +++ b/resources/i18n/fr.json @@ -68,7 +68,7 @@ "MyEnvironments": "Mes environnements", "ResourcePolicy": "Politique des ressources" }, - "YouAreOffline": "Vous êtes maintenant hors ligne", + "YouAreOffline": "Hors ligne : N'est connecté à aucun réseau.", "YouAreOnline": "Vous êtes maintenant en ligne", "NOTFOUND": "

Oups !
Page non trouvée...

", "DescNOTFOUND": "Désolé, la page que vous recherchez est introuvable.", diff --git a/resources/i18n/id.json b/resources/i18n/id.json index 5dfa85c427..4b74eddd01 100644 --- a/resources/i18n/id.json +++ b/resources/i18n/id.json @@ -68,7 +68,7 @@ "MyEnvironments": "Lingkungan Saya", "ResourcePolicy": "Kebijakan Sumber Daya" }, - "YouAreOffline": "Anda sekarang offline", + "YouAreOffline": "Offline: Tidak terhubung ke jaringan apa pun.", "YouAreOnline": "Anda sekarang online", "NOTFOUND": "

Ups!
Halaman tidak ditemukan...

", "DescNOTFOUND": "Maaf, halaman yang anda cari tidak ditemukan.", diff --git a/resources/i18n/it.json b/resources/i18n/it.json index 8146dbd297..de99ccf7cb 100644 --- a/resources/i18n/it.json +++ b/resources/i18n/it.json @@ -68,7 +68,7 @@ "MyEnvironments": "I miei ambienti", "ResourcePolicy": "Politica delle risorse" }, - "YouAreOffline": "Ora sei offline", + "YouAreOffline": "Non in linea: Non è collegato ad alcuna rete.", "YouAreOnline": "Ora sei online", "NOTFOUND": "

Ops!
Pagina non trovata...

", "DescNOTFOUND": "Siamo spiacenti, la pagina che stai cercando non è stata trovata.", diff --git a/resources/i18n/ja.json b/resources/i18n/ja.json index 7d9041d814..c8f98ff540 100644 --- a/resources/i18n/ja.json +++ b/resources/i18n/ja.json @@ -68,7 +68,7 @@ "MyEnvironments": "私の環境", "ResourcePolicy": "リソースポリシー" }, - "YouAreOffline": "あなたは今オフラインです", + "YouAreOffline": "オフライン:どのネットワークにも接続されていない。", "YouAreOnline": "あなたは今オンラインです", "NOTFOUND": "

おっと!
ページが見つかりません...

", "DescNOTFOUND": "申し訳ありませんが、お探しのページが見つかりませんでした。", diff --git a/resources/i18n/ko.json b/resources/i18n/ko.json index 4254236b51..411b34172d 100644 --- a/resources/i18n/ko.json +++ b/resources/i18n/ko.json @@ -68,7 +68,7 @@ "MyEnvironments": "나의 실행 환경", "ResourcePolicy": "자원 정책" }, - "YouAreOffline": "오프라인 상태가 되었습니다", + "YouAreOffline": "오프라인: 네트워크에 연결되어 있지 않습니다.", "YouAreOnline": "온라인 상태가 되었습니다", "NOTFOUND": "

요청하신 페이지를 찾을 수 없습니다.

", "DescNOTFOUND": "요청하신 페이지가 사라졌거나, 잘못된 경로를 입력하였습니다.", diff --git a/resources/i18n/mn.json b/resources/i18n/mn.json index 44a9831858..b2b980f3ee 100644 --- a/resources/i18n/mn.json +++ b/resources/i18n/mn.json @@ -68,7 +68,7 @@ "MyEnvironments": "Миний орчин", "ResourcePolicy": "Нөөцийн бодлого" }, - "YouAreOffline": "Та одоо офлайн байна", + "YouAreOffline": "Офлайн: Ямар ч сүлжээнд холбогдоогүй.", "YouAreOnline": "Та одоо онлайн байна", "NOTFOUND": "

Өө!
хуудас олдсонгүй ...

", "DescNOTFOUND": "Уучлаарай, таны хайж буй хуудас олдсонгүй.", diff --git a/resources/i18n/ms.json b/resources/i18n/ms.json index 847a8db145..7d57f4f9b3 100644 --- a/resources/i18n/ms.json +++ b/resources/i18n/ms.json @@ -68,7 +68,7 @@ "MyEnvironments": "Persekitaran Saya", "ResourcePolicy": "Dasar Sumber" }, - "YouAreOffline": "Anda kini berada di luar talian", + "YouAreOffline": "Luar talian: Tidak disambungkan ke mana-mana rangkaian.", "YouAreOnline": "Anda kini dalam talian", "NOTFOUND": "

Alamak!
Halaman tidak dijumpai ...

", "DescNOTFOUND": "Maaf, halaman yang anda cari tidak dapat dijumpai.", diff --git a/resources/i18n/pl.json b/resources/i18n/pl.json index a5ad1ec575..c288e77a9b 100644 --- a/resources/i18n/pl.json +++ b/resources/i18n/pl.json @@ -68,7 +68,7 @@ "MyEnvironments": "Moje Środowiska", "ResourcePolicy": "Polityka zasobów" }, - "YouAreOffline": "Jesteś teraz offline", + "YouAreOffline": "Offline: Brak połączenia z siecią.", "YouAreOnline": "Jesteś teraz online", "NOTFOUND": "

Ups!
Nie znaleziono strony...

", "DescNOTFOUND": "Przepraszamy, nie można znaleźć strony, której szukasz.", diff --git a/resources/i18n/pt-BR.json b/resources/i18n/pt-BR.json index f241397c42..1bdce1a09c 100644 --- a/resources/i18n/pt-BR.json +++ b/resources/i18n/pt-BR.json @@ -68,7 +68,7 @@ "MyEnvironments": "Meus ambientes", "ResourcePolicy": "Política de Recursos" }, - "YouAreOffline": "Agora você está offline", + "YouAreOffline": "Desligado: Não está ligado a nenhuma rede.", "YouAreOnline": "Agora você está online", "NOTFOUND": "

Ops!
Página não encontrada ...

", "DescNOTFOUND": "Desculpe, a página que você está procurando não foi encontrada.", diff --git a/resources/i18n/pt.json b/resources/i18n/pt.json index 59971597d7..4f3ebe8fef 100644 --- a/resources/i18n/pt.json +++ b/resources/i18n/pt.json @@ -68,7 +68,7 @@ "MyEnvironments": "Meus ambientes", "ResourcePolicy": "Política de Recursos" }, - "YouAreOffline": "Agora você está offline", + "YouAreOffline": "Desligado: Não está ligado a nenhuma rede.", "YouAreOnline": "Agora você está online", "NOTFOUND": "

Ops!
Página não encontrada ...

", "DescNOTFOUND": "Desculpe, a página que você está procurando não foi encontrada.", diff --git a/resources/i18n/ru.json b/resources/i18n/ru.json index 0b52912774..411cd34e87 100644 --- a/resources/i18n/ru.json +++ b/resources/i18n/ru.json @@ -68,7 +68,7 @@ "MyEnvironments": "Моя среда", "ResourcePolicy": "Ресурсная политика" }, - "YouAreOffline": "Вы сейчас не в сети", + "YouAreOffline": "Не в сети: Не подключен ни к одной сети.", "YouAreOnline": "Вы сейчас в сети", "NOTFOUND": "

Ой!
Страница не найдена ...

", "DescNOTFOUND": "Извините, страница, которую вы ищете, не может быть найдена.", diff --git a/resources/i18n/tr.json b/resources/i18n/tr.json index 0d57188532..89ef6c935d 100644 --- a/resources/i18n/tr.json +++ b/resources/i18n/tr.json @@ -68,7 +68,7 @@ "MyEnvironments": "Ortamlarım", "ResourcePolicy": "Kaynak Politikası" }, - "YouAreOffline": "Şu anda çevrimdışısın", + "YouAreOffline": "Çevrimdışı: Herhangi bir ağa bağlı değil.", "YouAreOnline": "artık çevrimiçisin", "NOTFOUND": "

Hata!
Sayfa Bulunamadı...

", "DescNOTFOUND": "Üzgünüz, aradığınız sayfa bulunamadı.", diff --git a/resources/i18n/vi.json b/resources/i18n/vi.json index 251f61aa12..bda6b26633 100644 --- a/resources/i18n/vi.json +++ b/resources/i18n/vi.json @@ -68,7 +68,7 @@ "MyEnvironments": "Môi trường của tôi", "ResourcePolicy": "Chính sách tài nguyên" }, - "YouAreOffline": "Bạn hiện đang ngoại tuyến", + "YouAreOffline": "Ngoại tuyến: Không kết nối với bất kỳ mạng nào.", "YouAreOnline": "Bạn hiện đang trực tuyến", "NOTFOUND": "

Rất tiếc!
Không tìm thấy trang ...

", "DescNOTFOUND": "Xin lỗi, không thể tìm thấy trang bạn đang tìm.", diff --git a/resources/i18n/zh-CN.json b/resources/i18n/zh-CN.json index bee577bebf..a3af896a6a 100644 --- a/resources/i18n/zh-CN.json +++ b/resources/i18n/zh-CN.json @@ -68,7 +68,7 @@ "MyEnvironments": "我的环境", "ResourcePolicy": "资源政策" }, - "YouAreOffline": "您现在离线", + "YouAreOffline": "脱机:未连接任何网络。", "YouAreOnline": "您现在在线", "NOTFOUND": "

糟糕!
页面未找到...

", "DescNOTFOUND": "抱歉,找不到您要找的页面。", diff --git a/resources/i18n/zh-TW.json b/resources/i18n/zh-TW.json index ac2a404fb3..d55c426d5c 100644 --- a/resources/i18n/zh-TW.json +++ b/resources/i18n/zh-TW.json @@ -68,7 +68,7 @@ "MyEnvironments": "我的環境", "ResourcePolicy": "資源政策" }, - "YouAreOffline": "您現在離線", + "YouAreOffline": "脱机:未连接任何网络。", "YouAreOnline": "您現在在線", "NOTFOUND": "

糟糕!
頁面未找到...

", "DescNOTFOUND": "抱歉,找不到您要找的頁面。", diff --git a/src/backend-ai-app.ts b/src/backend-ai-app.ts index 8050c44bc9..cf7046a1dc 100644 --- a/src/backend-ai-app.ts +++ b/src/backend-ai-app.ts @@ -5,8 +5,6 @@ export const UPDATE_PAGE = 'UPDATE_PAGE'; export const UPDATE_OFFLINE = 'UPDATE_OFFLINE'; export const UPDATE_DRAWER_STATE = 'UPDATE_DRAWER_STATE'; -export const OPEN_SNACKBAR = 'OPEN_SNACKBAR'; -export const CLOSE_SNACKBAR = 'CLOSE_SNACKBAR'; export const navigate = (path: any, params: Record = {}) => @@ -192,30 +190,6 @@ const updatePage = (page, params) => { }; }; -let offlineTimer; - -export const showOffline = () => (dispatch) => { - dispatch({ - type: OPEN_SNACKBAR, - }); - window.clearTimeout(offlineTimer); - offlineTimer = window.setTimeout( - () => dispatch({ type: CLOSE_SNACKBAR }), - 3000, - ); -}; - -export const updateOffline = (offline) => (dispatch, getState) => { - // Show the snackbar only if offline status changes. - if (offline !== getState().app.offline) { - dispatch(showOffline()); - } - dispatch({ - type: UPDATE_OFFLINE, - offline, - }); -}; - export const updateDrawerState = (opened) => { return { type: UPDATE_DRAWER_STATE, diff --git a/src/components/backend-ai-offline-indicator.ts b/src/components/backend-ai-offline-indicator.ts deleted file mode 100644 index 97832181ae..0000000000 --- a/src/components/backend-ai-offline-indicator.ts +++ /dev/null @@ -1,68 +0,0 @@ -/** - @license - Copyright (c) 2015-2024 Lablup Inc. All rights reserved. - */ -import { css, CSSResultGroup, html, LitElement } from 'lit'; -import { customElement } from 'lit/decorators.js'; - -/** - Backend.AI Offline Indicator - - Example: - - - -@group Backend.AI Web UI - @element backend-ai-offline-indicator - */ - -@customElement('backend-ai-offline-indicator') -export default class BackendAIOfflineIndicator extends LitElement { - static get styles(): CSSResultGroup | undefined { - return [ - css` - :host { - display: block; - position: fixed; - top: 100%; - left: 0; - right: 0; - padding: 12px; - background-color: #246; - color: white; - box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); - text-align: center; - will-change: transform; - transform: translate3d(0, 0, 0); - transition-property: visibility, transform; - transition-duration: 0.2s; - visibility: hidden; - } - - :host([active]) { - visibility: visible; - transform: translate3d(0, -100%, 0); - } - - @media (min-width: 460px) { - :host { - width: 320px; - margin: auto; - } - } - `, - ]; - } - - render() { - return html` - - `; - } -} - -declare global { - interface HTMLElementTagNameMap { - 'backend-ai-offline-indicator': BackendAIOfflineIndicator; - } -} diff --git a/src/components/backend-ai-webui.ts b/src/components/backend-ai-webui.ts index dcec0fc4e9..c9e9efbe4e 100644 --- a/src/components/backend-ai-webui.ts +++ b/src/components/backend-ai-webui.ts @@ -2,7 +2,7 @@ @license Copyright (c) 2015-2024 Lablup Inc. All rights reserved. */ -import { navigate, updateOffline } from '../backend-ai-app'; +import { navigate } from '../backend-ai-app'; // import '../lib/backend.ai-client-esm'; import { default as TabCount } from '../lib/TabCounter'; import { @@ -19,7 +19,6 @@ import './backend-ai-help-button'; import './backend-ai-indicator-pool'; import './backend-ai-login'; import BackendAIMetadataStore from './backend-ai-metadata-store'; -import './backend-ai-offline-indicator'; import { BackendAIPage } from './backend-ai-page'; import './backend-ai-project-switcher'; import './backend-ai-resource-broker'; @@ -52,7 +51,6 @@ import { customElement, property, query } from 'lit/decorators.js'; import toml from 'markty-toml'; // PWA components import { connect } from 'pwa-helpers/connect-mixin'; -import { installOfflineWatcher } from 'pwa-helpers/network'; import { installRouter } from 'pwa-helpers/router'; registerTranslateConfig({ @@ -107,7 +105,6 @@ export default class BackendAIWebUI extends connect(store)(LitElement) { | 'feedback' | 'notification' | 'task' = ''; - @property({ type: Boolean }) _offlineIndicatorOpened = false; @property({ type: Boolean }) _offline = false; @property({ type: Object }) config = Object(); @property({ type: Object }) notification; @@ -236,7 +233,6 @@ export default class BackendAIWebUI extends connect(store)(LitElement) { installRouter((location) => store.dispatch(navigate(decodeURIComponent(location.pathname))), ); - installOfflineWatcher((offline) => store.dispatch(updateOffline(offline))); let configPath; if (globalThis.isElectron) { configPath = './config.toml'; @@ -867,7 +863,6 @@ export default class BackendAIWebUI extends connect(store)(LitElement) { this._page = state.app.page; this._pageParams = state.app.params; this._offline = state.app.offline; - this._offlineIndicatorOpened = state.app.offlineIndicatorOpened; // this._drawerOpened = state.app.drawerOpened; globalThis.currentPage = this._page; globalThis.currentPageParams = this._pageParams; @@ -966,9 +961,7 @@ export default class BackendAIWebUI extends connect(store)(LitElement) { - - ${this._offline ? _t('webui.YouAreOffline') : _t('webui.YouAreOnline')}. - + diff --git a/src/reducers/app.ts b/src/reducers/app.ts index b0243f3b6f..c7eb4aad4d 100644 --- a/src/reducers/app.ts +++ b/src/reducers/app.ts @@ -36,16 +36,6 @@ const app = (state = INITIAL_STATE, action) => { ...state, drawerOpened: action.opened, }; - case OPEN_SNACKBAR: - return { - ...state, - offlineIndicatorOpened: true, - }; - case CLOSE_SNACKBAR: - return { - ...state, - offlineIndicatorOpened: false, - }; default: return state; } diff --git a/src/types/backend-ai-console.d.ts b/src/types/backend-ai-console.d.ts index eeb3a48132..bae36fa078 100644 --- a/src/types/backend-ai-console.d.ts +++ b/src/types/backend-ai-console.d.ts @@ -4,7 +4,6 @@ import './backend-ai-dialog'; import './backend-ai-help-button'; import './backend-ai-indicator-pool'; import './backend-ai-login'; -import './backend-ai-offline-indicator'; import './backend-ai-resource-broker'; import './backend-ai-settings-store'; import './backend-ai-sidepanel-notification';