diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bfe42ac75..044325707 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -93,7 +93,7 @@ jobs: - run: yarn install-deps - name: "Build frontend with env vars" run: yarn build:frontend - env: + env: NODE_ENV: production DEV_RPC: https://rpc-gate.autonolas.tech/gnosis-rpc/ IS_STAGING: ${{ github.ref != 'refs/heads/main' && 'true' || 'false' }} @@ -110,4 +110,26 @@ jobs: NODE_ENV: production DEV_RPC: https://rpc-gate.autonolas.tech/gnosis-rpc/ FORK_URL: https://rpc-gate.autonolas.tech/gnosis-rpc/ - run: node build.js \ No newline at end of file + run: node build.js + - name: "Build frontend with dev env vars" + run: yarn build:frontend + env: + NODE_ENV: development + DEV_RPC: https://virtual.gnosis.rpc.tenderly.co/78ca845d-2b24-44a6-9ce2-869a979e8b5b + IS_STAGING: ${{ github.ref != 'refs/heads/main' && 'true' || 'false' }} + FORK_URL: https://virtual.gnosis.rpc.tenderly.co/78ca845d-2b24-44a6-9ce2-869a979e8b5b + - name: "Build, notarize, publish dev build" + env: + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLEIDPASS }} + APPLE_ID: ${{ secrets.APPLEID }} + APPLETEAMID: ${{ secrets.APPLETEAMID }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + CSC_LINK: ${{ secrets.CSC_LINK }} + GH_TOKEN: ${{ secrets.github_token}} + NODE_ENV: development + DEV_RPC: https://virtual.gnosis.rpc.tenderly.co/78ca845d-2b24-44a6-9ce2-869a979e8b5b + FORK_URL: https://virtual.gnosis.rpc.tenderly.co/78ca845d-2b24-44a6-9ce2-869a979e8b5b + run: | + echo "DEV_RPC=https://virtual.gnosis.rpc.tenderly.co/78ca845d-2b24-44a6-9ce2-869a979e8b5b" >> .env + echo -e "FORK_URL=https://virtual.gnosis.rpc.tenderly.co/78ca845d-2b24-44a6-9ce2-869a979e8b5b" >> .env + node build.js \ No newline at end of file diff --git a/build.js b/build.js index a7e15a32b..fa1e1b0db 100644 --- a/build.js +++ b/build.js @@ -6,6 +6,16 @@ const build = require('electron-builder').build; const { publishOptions } = require('./electron/constants'); +/** + * Get the artifact name for the build based on the environment. + * @returns {string} + */ +function artifactName() { + const env = process.env.NODE_ENV; + const prefix = env === 'production' ? '' : 'dev-'; + return prefix + '${productName}-${version}-${platform}-${arch}.${ext}'; +} + const main = async () => { console.log('Building...'); @@ -14,7 +24,7 @@ const main = async () => { publish: 'onTag', config: { appId: 'xyz.valory.olas-operate-app', - artifactName: '${productName}-${version}-${platform}-${arch}.${ext}', + artifactName: artifactName(), productName: 'Pearl', files: ['electron/**/*', 'package.json'], directories: { @@ -26,6 +36,10 @@ const main = async () => { to: 'bins', filter: ['**/*'], }, + { + from: '.env', + to: '.env' + }, ], cscKeyPassword: process.env.CSC_KEY_PASSWORD, cscLink: process.env.CSC_LINK, diff --git a/build_pearl.sh b/build_pearl.sh new file mode 100755 index 000000000..65e5d4ac9 --- /dev/null +++ b/build_pearl.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# ------------------------------------------------------------------------------ +# +# Copyright 2023-2024 Valory AG +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ------------------------------------------------------------------------------ + +cd "$(dirname "$0")" + +BIN_DIR="electron/bins/" +mkdir -p $BIN_DIR + +poetry install + +poetry run pyinstaller operate/services/utils/tendermint.py --onefile --distpath $BIN_DIR + +poetry run pyinstaller \ + --collect-data eth_account \ + --collect-all aea \ + --collect-all autonomy \ + --collect-all operate \ + --collect-all aea_ledger_ethereum \ + --collect-all aea_ledger_cosmos \ + --collect-all aea_ledger_ethereum_flashbots \ + --hidden-import aea_ledger_ethereum \ + --hidden-import aea_ledger_cosmos \ + --hidden-import aea_ledger_ethereum_flashbots \ + operate/pearl.py \ + --add-binary ${BIN_DIR}/aea_bin_x64:. \ + --add-binary ${BIN_DIR}/aea_bin_arm64:. \ + --onefile \ + --distpath $BIN_DIR \ + --name pearl_$(uname -m) + diff --git a/download_binaries.sh b/download_binaries.sh new file mode 100755 index 000000000..db12c6223 --- /dev/null +++ b/download_binaries.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +BIN_DIR="electron/bins/" +mkdir -p $BIN_DIR + +trader_version=$(poetry run python -c "import yaml; config = yaml.safe_load(open('templates/trader.yaml')); print(config['configuration']['trader_version'])") + +curl -L -o "${BIN_DIR}aea_bin_x64" "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_x64" + +curl -L -o "${BIN_DIR}aea_bin_arm64" "https://github.com/valory-xyz/trader/releases/download/${trader_version}/trader_bin_arm64" diff --git a/electron/install.js b/electron/install.js index ac60b76b3..9da1dcad6 100644 --- a/electron/install.js +++ b/electron/install.js @@ -14,7 +14,17 @@ const { paths } = require('./constants'); * - use "" (nothing as a suffix) for latest release candidate, for example "0.1.0rc26" * - use "alpha" for alpha release, for example "0.1.0rc26-alpha" */ -const OlasMiddlewareVersion = '0.1.0rc110'; +const OlasMiddlewareVersion = '0.1.0rc111'; + +const path = require('path'); +const { app } = require('electron'); + +// load env vars +require('dotenv').config({ + path: app.isPackaged + ? path.join(process.resourcesPath, '.env') + : path.resolve(process.cwd(), '.env'), +}); const Env = { ...process.env, diff --git a/electron/main.js b/electron/main.js index e2c66a668..5a01cae73 100644 --- a/electron/main.js +++ b/electron/main.js @@ -131,17 +131,18 @@ const createTray = () => { tray.setContextMenu(contextMenu); ipcMain.on('tray', (_event, status) => { + const isSupportedOS = isWindows || isMac; switch (status) { case 'low-gas': { const icon = getUpdatedTrayIcon( - isWindows || isMac ? TRAY_ICONS.LOW_GAS : TRAY_ICONS_PATHS.LOW_GAS, + isSupportedOS ? TRAY_ICONS.LOW_GAS : TRAY_ICONS_PATHS.LOW_GAS, ); tray.setImage(icon); break; } case 'running': { const icon = getUpdatedTrayIcon( - isWindows || isMac ? TRAY_ICONS.RUNNING : TRAY_ICONS_PATHS.RUNNING, + isSupportedOS ? TRAY_ICONS.RUNNING : TRAY_ICONS_PATHS.RUNNING, ); tray.setImage(icon); @@ -149,7 +150,14 @@ const createTray = () => { } case 'paused': { const icon = getUpdatedTrayIcon( - isWindows || isMac ? TRAY_ICONS.PAUSED : TRAY_ICONS_PATHS.PAUSED, + isSupportedOS ? TRAY_ICONS.PAUSED : TRAY_ICONS_PATHS.PAUSED, + ); + tray.setImage(icon); + break; + } + case 'logged-out': { + const icon = getUpdatedTrayIcon( + isSupportedOS ? TRAY_ICONS.LOGGED_OUT : TRAY_ICONS_PATHS.LOGGED_OUT, ); tray.setImage(icon); break; diff --git a/electron/store.js b/electron/store.js index 5577decff..afbc7f62d 100644 --- a/electron/store.js +++ b/electron/store.js @@ -4,6 +4,7 @@ const defaultSchema = { isInitialFunded: { type: 'boolean', default: false }, firstStakingRewardAchieved: { type: 'boolean', default: false }, firstRewardNotificationShown: { type: 'boolean', default: false }, + agentEvictionAlertShown: { type: 'boolean', default: false }, }; const setupStoreIpc = async (ipcChannel, mainWindow, storeInitialValues) => { diff --git a/frontend/components/Main/MainGasBalance.tsx b/frontend/components/Main/MainGasBalance.tsx index 3f8e77487..0d1f83f26 100644 --- a/frontend/components/Main/MainGasBalance.tsx +++ b/frontend/components/Main/MainGasBalance.tsx @@ -1,11 +1,13 @@ import { ArrowUpOutlined, InfoCircleOutlined } from '@ant-design/icons'; import { Skeleton, Tooltip, Typography } from 'antd'; -import { useMemo } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import styled from 'styled-components'; import { COLOR } from '@/constants/colors'; import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; +import { useElectronApi } from '@/hooks/useElectronApi'; +import { useStore } from '@/hooks/useStore'; import { useWallet } from '@/hooks/useWallet'; import { CardSection } from '../styled/CardSection'; @@ -30,20 +32,43 @@ const EmptyDot = styled(Dot)` const FineDot = styled(Dot)` background-color: ${COLOR.GREEN_2}; `; -const LowDot = styled(Dot)` - background-color: ${COLOR.ORANGE}; -`; const BalanceStatus = () => { - const { safeBalance } = useBalance(); + const { isBalanceLoaded, safeBalance } = useBalance(); + const { storeState } = useStore(); + const { showNotification } = useElectronApi(); - const status = useMemo(() => { - if (!safeBalance || safeBalance.ETH === 0) { - return { statusName: 'Empty', StatusComponent: EmptyDot }; + const [isLowBalanceNotificationShown, setIsLowBalanceNotificationShown] = + useState(false); + + // show notification if balance is too low + useEffect(() => { + if (!isBalanceLoaded) return; + if (!safeBalance) return; + if (!showNotification) return; + if (!storeState?.isInitialFunded) return; + + if (safeBalance.ETH < LOW_BALANCE && !isLowBalanceNotificationShown) { + showNotification('Trading balance is too low.'); + setIsLowBalanceNotificationShown(true); } - if (safeBalance.ETH < LOW_BALANCE) { - return { statusName: 'Low', StatusComponent: LowDot }; + // If it has already been shown and the balance has increased, + // should show the notification again if it goes below the threshold. + if (safeBalance.ETH >= LOW_BALANCE && isLowBalanceNotificationShown) { + setIsLowBalanceNotificationShown(false); + } + }, [ + isBalanceLoaded, + isLowBalanceNotificationShown, + safeBalance, + showNotification, + storeState?.isInitialFunded, + ]); + + const status = useMemo(() => { + if (!safeBalance || safeBalance.ETH < LOW_BALANCE) { + return { statusName: 'Too low', StatusComponent: EmptyDot }; } return { statusName: 'Fine', StatusComponent: FineDot }; diff --git a/frontend/components/Main/MainHeader/AgentButton/index.tsx b/frontend/components/Main/MainHeader/AgentButton/index.tsx index cd6f72c59..356a45c12 100644 --- a/frontend/components/Main/MainHeader/AgentButton/index.tsx +++ b/frontend/components/Main/MainHeader/AgentButton/index.tsx @@ -4,6 +4,7 @@ import { useCallback, useMemo } from 'react'; import { Chain, DeploymentStatus } from '@/client'; import { COLOR } from '@/constants/colors'; +import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; import { useElectronApi } from '@/hooks/useElectronApi'; import { useServices } from '@/hooks/useServices'; @@ -15,7 +16,10 @@ import { ServicesService } from '@/service/Services'; import { WalletService } from '@/service/Wallet'; import { getMinimumStakedAmountRequired } from '@/utils/service'; -import { CannotStartAgent } from '../CannotStartAgent'; +import { + CannotStartAgent, + CannotStartAgentDueToUnexpectedError, +} from '../CannotStartAgent'; import { requiredGas, requiredOlas } from '../constants'; const { Text } = Typography; @@ -185,6 +189,15 @@ const AgentNotRunningButton = () => { ]); const isDeployable = useMemo(() => { + // if the agent is NOT running and the balance is too low, + // user should not be able to start the agent + const isServiceInactive = + serviceStatus === DeploymentStatus.BUILT || + serviceStatus === DeploymentStatus.STOPPED; + if (isServiceInactive && safeBalance && safeBalance.ETH < LOW_BALANCE) { + return false; + } + if (serviceStatus === DeploymentStatus.DEPLOYED) return false; if (serviceStatus === DeploymentStatus.DEPLOYING) return false; if (serviceStatus === DeploymentStatus.STOPPING) return false; @@ -211,6 +224,7 @@ const AgentNotRunningButton = () => { serviceStatus, storeState?.isInitialFunded, totalEthBalance, + safeBalance, ]); const buttonProps: ButtonProps = { @@ -258,11 +272,7 @@ export const AgentButton = () => { return ; } - return ( - - ); + return ; }, [ hasInitialLoaded, serviceStatus, diff --git a/frontend/components/Main/MainHeader/AgentHead/index.tsx b/frontend/components/Main/MainHeader/AgentHead.tsx similarity index 100% rename from frontend/components/Main/MainHeader/AgentHead/index.tsx rename to frontend/components/Main/MainHeader/AgentHead.tsx diff --git a/frontend/components/Main/MainHeader/CannotStartAgent.tsx b/frontend/components/Main/MainHeader/CannotStartAgent.tsx index 9206d6fa0..556512f5d 100644 --- a/frontend/components/Main/MainHeader/CannotStartAgent.tsx +++ b/frontend/components/Main/MainHeader/CannotStartAgent.tsx @@ -15,6 +15,32 @@ const cannotStartAgentText = ( ); +const otherPopoverProps: PopoverProps = { + arrow: false, + placement: 'bottomRight', +}; + +export const CannotStartAgentDueToUnexpectedError = () => ( + + + Try to restart the app. If the issue persists, join the Olas community + Discord server to report or stay up to date on the issue. + + + + Olas community Discord server {UNICODE_SYMBOLS.EXTERNAL_LINK} + + + } + > + {cannotStartAgentText} + +); + const evictedDescription = "You didn't run your agent enough and it missed its targets multiple times. Please wait a few days and try to run your agent again."; const AgentEvictedPopover = () => ( @@ -27,11 +53,6 @@ const AgentEvictedPopover = () => ( ); -const otherPopoverProps: PopoverProps = { - arrow: false, - placement: 'bottomRight', -}; - const JoinOlasCommunity = () => (
diff --git a/frontend/components/Main/MainHeader/index.tsx b/frontend/components/Main/MainHeader/index.tsx index c24b0d430..78ffde06f 100644 --- a/frontend/components/Main/MainHeader/index.tsx +++ b/frontend/components/Main/MainHeader/index.tsx @@ -23,6 +23,8 @@ const useSetupTrayIcon = () => { setTrayIcon?.('running'); } else if (serviceStatus === DeploymentStatus.STOPPED) { setTrayIcon?.('paused'); + } else if (serviceStatus === DeploymentStatus.BUILT) { + setTrayIcon?.('logged-out'); } }, [safeBalance, serviceStatus, setTrayIcon]); diff --git a/frontend/components/Main/MainNeedsFunds.tsx b/frontend/components/Main/MainNeedsFunds.tsx index f275136bf..71464a615 100644 --- a/frontend/components/Main/MainNeedsFunds.tsx +++ b/frontend/components/Main/MainNeedsFunds.tsx @@ -1,6 +1,7 @@ import { Flex, Typography } from 'antd'; import { formatUnits } from 'ethers/lib/utils'; import { ReactNode, useEffect, useMemo } from 'react'; +import styled from 'styled-components'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; import { useBalance } from '@/hooks/useBalance'; @@ -12,9 +13,16 @@ import { getMinimumStakedAmountRequired } from '@/utils/service'; import { Alert } from '../Alert'; import { CardSection } from '../styled/CardSection'; -const { Text, Paragraph } = Typography; +const { Text } = Typography; const COVER_PREV_BLOCK_BORDER_STYLE = { marginTop: '-1px' }; +const FundingValue = styled.div` + font-size: 24px; + font-weight: 700; + line-height: 32px; + letter-spacing: -0.72px; +`; + const useNeedsFunds = () => { const { getServiceTemplates } = useServiceTemplates(); @@ -94,29 +102,28 @@ export const MainNeedsFunds = () => { const message: ReactNode = useMemo( () => ( - - Your agent needs funds - - USE THE ACCOUNT CREDENTIALS PROVIDED IN THE “ADD FUNDS” INSTRUCTIONS - BELOW. - - - To run your agent, you must add these amounts to your account: - - {!hasEnoughOlasForInitialFunding && ( - - {`${UNICODE_SYMBOLS.OLAS}${serviceFundRequirements.olas} OLAS `} - - for staking. - - )} - {!hasEnoughEthForInitialFunding && ( - - - {`${serviceFundRequirements.eth} XDAI `} - - - for trading balance. - - )} + + Your agent needs funds + + {!hasEnoughOlasForInitialFunding && ( +
+ {`${UNICODE_SYMBOLS.OLAS}${serviceFundRequirements.olas} OLAS `} + for staking +
+ )} + {!hasEnoughEthForInitialFunding && ( +
+ + {`$${serviceFundRequirements.eth} XDAI `} + + for trading +
+ )} +
+
    +
  • Do not add more than these amounts.
  • +
  • Use the address in the “Add Funds” section below.
  • +
), [ diff --git a/frontend/components/Main/MainOlasBalance.tsx b/frontend/components/Main/MainOlasBalance.tsx index f51cf2ef9..fa6d87b9b 100644 --- a/frontend/components/Main/MainOlasBalance.tsx +++ b/frontend/components/Main/MainOlasBalance.tsx @@ -1,17 +1,21 @@ import { InfoCircleOutlined } from '@ant-design/icons'; -import { Flex, Skeleton, Tooltip, Typography } from 'antd'; +import { Button, Flex, Skeleton, Tooltip, Typography } from 'antd'; import { useMemo } from 'react'; import styled from 'styled-components'; +import { Alert } from '@/components/Alert'; import { COLOR } from '@/constants/colors'; import { UNICODE_SYMBOLS } from '@/constants/symbols'; +import { LOW_BALANCE } from '@/constants/thresholds'; import { useBalance } from '@/hooks/useBalance'; +import { useElectronApi } from '@/hooks/useElectronApi'; import { useReward } from '@/hooks/useReward'; +import { useStore } from '@/hooks/useStore'; import { balanceFormat } from '@/utils/numberFormatters'; import { CardSection } from '../styled/CardSection'; -const { Text } = Typography; +const { Text, Title } = Typography; const Balance = styled.span` letter-spacing: -2px; margin-right: 4px; @@ -103,9 +107,104 @@ const CurrentBalance = () => { ); }; +const MainOlasBalanceAlert = styled.div` + .ant-alert { + margin-bottom: 8px; + .anticon.ant-alert-icon { + height: 20px; + width: 20px; + svg { + width: 100%; + height: 100%; + } + } + } +`; + +const LowTradingBalanceAlert = () => { + const { isBalanceLoaded, safeBalance } = useBalance(); + const { storeState } = useStore(); + + if (!isBalanceLoaded) return null; + if (!safeBalance) return null; + if (!storeState?.isInitialFunded) return; + if (safeBalance.ETH >= LOW_BALANCE) return null; + + return ( + + + + Trading balance is too low + + + {`To run your agent, add at least $${LOW_BALANCE} XDAI to your account.`} + + + Do it quickly to avoid your agent missing its targets and getting + suspended! + +
+ } + /> + + ); +}; + +const AvoidSuspensionAlert = () => { + const { store } = useElectronApi(); + + return ( + + + + Avoid suspension! + + + Run your agent for at least half an hour a day to make sure it + hits its targets. If it misses its targets 2 days in a row, it’ll + be suspended. You won’t be able to run it or earn rewards for + several days. + + + + } + /> + + ); +}; + export const MainOlasBalance = () => { + const { storeState } = useStore(); const { isBalanceLoaded, totalOlasBalance } = useBalance(); + // If first reward notification is shown BUT + // agent eviction alert is NOT yet shown, show this alert. + const canShowAvoidSuspensionAlert = useMemo(() => { + if (!storeState) return false; + + return ( + storeState.firstRewardNotificationShown && + !storeState.agentEvictionAlertShown + ); + }, [storeState]); + const balance = useMemo(() => { if (totalOlasBalance === undefined) return '--'; return balanceFormat(totalOlasBalance, 2); @@ -113,6 +212,8 @@ export const MainOlasBalance = () => { return ( + {canShowAvoidSuspensionAlert ? : null} + {isBalanceLoaded ? ( <> diff --git a/frontend/components/Main/MainRewards.tsx b/frontend/components/Main/MainRewards.tsx index 8f775b163..50ef32f30 100644 --- a/frontend/components/Main/MainRewards.tsx +++ b/frontend/components/Main/MainRewards.tsx @@ -65,7 +65,7 @@ const DisplayRewards = () => { const SHARE_TEXT = `I just earned my first reward through the Operate app powered by #olas!\n\nDownload the Pearl app:`; const OPERATE_URL = 'https://olas.network/operate?pearl=first-reward'; -const NotifyRewards = () => { +const NotifyRewardsModal = () => { const { isEligibleForRewards, availableRewardsForEpochEth } = useReward(); const { totalOlasBalance } = useBalance(); const { showNotification, store } = useElectronApi(); @@ -179,6 +179,6 @@ const NotifyRewards = () => { export const MainRewards = () => ( <> - + ); diff --git a/frontend/constants/thresholds.ts b/frontend/constants/thresholds.ts index ced09c8c5..fb5ab3515 100644 --- a/frontend/constants/thresholds.ts +++ b/frontend/constants/thresholds.ts @@ -7,4 +7,4 @@ export const MIN_ETH_BALANCE_THRESHOLDS = { }, }; -export const LOW_BALANCE = 0.5; +export const LOW_BALANCE = 2; diff --git a/frontend/pages/_app.tsx b/frontend/pages/_app.tsx index 7a6c2efe8..68727cf8c 100644 --- a/frontend/pages/_app.tsx +++ b/frontend/pages/_app.tsx @@ -2,7 +2,7 @@ import '../styles/globals.scss'; import { ConfigProvider } from 'antd'; import type { AppProps } from 'next/app'; -import { useEffect, useRef } from 'react'; +import { useEffect, useState } from 'react'; import { Layout } from '@/components/Layout'; import { BalanceProvider } from '@/context/BalanceProvider'; @@ -20,13 +20,9 @@ import { WalletProvider } from '@/context/WalletProvider'; import { mainTheme } from '@/theme'; export default function App({ Component, pageProps }: AppProps) { - const isMounted = useRef(false); - + const [isMounted, setIsMounted] = useState(false); useEffect(() => { - isMounted.current = true; - return () => { - isMounted.current = false; - }; + setIsMounted(true); }, []); return ( @@ -42,13 +38,13 @@ export default function App({ Component, pageProps }: AppProps) { - {isMounted ? ( - + + {isMounted ? ( - - ) : null} + ) : null} + diff --git a/frontend/styles/globals.scss b/frontend/styles/globals.scss index 13afcf16c..6999610fb 100644 --- a/frontend/styles/globals.scss +++ b/frontend/styles/globals.scss @@ -66,7 +66,7 @@ button, input, select, textarea, .ant-input-suffix { &--primary { border-color: #ECD7FE; background-color: #F8F0FF; - color: #36075F; + color: #7E22CE; .ant-alert-icon { color: #7E22CE; @@ -136,6 +136,10 @@ button, input, select, textarea, .ant-input-suffix { margin-top: 12px !important; } +.p-0 { + padding: 0 !important; +} + .mx-auto { margin-left: auto !important; margin-right: auto !important; diff --git a/frontend/types/ElectronApi.ts b/frontend/types/ElectronApi.ts index 2f586a0d9..61d551e8b 100644 --- a/frontend/types/ElectronApi.ts +++ b/frontend/types/ElectronApi.ts @@ -3,6 +3,11 @@ export type ElectronStore = { isInitialFunded?: boolean; firstStakingRewardAchieved?: boolean; firstRewardNotificationShown?: boolean; + agentEvictionAlertShown?: boolean; }; -export type ElectronTrayIconStatus = 'low-gas' | 'running' | 'paused'; +export type ElectronTrayIconStatus = + | 'low-gas' + | 'running' + | 'paused' + | 'logged-out'; diff --git a/operate/services/manage.py b/operate/services/manage.py index f1cb481a0..024ff0c28 100644 --- a/operate/services/manage.py +++ b/operate/services/manage.py @@ -99,8 +99,16 @@ def json(self) -> t.List[t.Dict]: continue if not path.name.startswith("bafybei"): continue - service = Service.load(path=path) - data.append(service.json) + try: + service = Service.load(path=path) + data.append(service.json) + except Exception as e: # pylint: disable=broad-except + self.logger.warning( + f"Failed to load service: {path.name}. Exception: {e}" + ) + # delete the invalid path + shutil.rmtree(path) + self.logger.info(f"Deleted invalid service: {path.name}") return data def exists(self, service: str) -> bool: diff --git a/package.json b/package.json index 23a69d72b..3388ad3f0 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "productName": "Pearl", "description": "An all-in-one application designed to streamline your entry into the world of autonomous agents and earning OLAS through staking.", "scripts": { - "build": "rm -rf dist/ && node build.tester.js", "build:frontend": "cd frontend && yarn build && rm -rf ../electron/.next && cp -r .next ../electron/.next && rm -rf ../electron/public && cp -r public ../electron/public", "dev:backend": "poetry run python operate/cli.py", "dev:frontend": "cd frontend && yarn dev", @@ -52,9 +51,13 @@ "install:backend": "poetry install --no-root", "install:frontend": "cd frontend && yarn", "lint:frontend": "cd frontend && yarn lint", - "start": "electron .", + "start": "yarn electron .", + "dev": "dotenv -e .env -- yarn start", "start:frontend": "cd frontend && yarn start", - "test:frontend": "cd frontend && yarn test" + "test:frontend": "cd frontend && yarn test", + "download-binaries": "sh download_binaries.sh", + "build:pearl": "sh build_pearl.sh" + }, - "version": "0.1.0-rc110" + "version": "0.1.0-rc111" } diff --git a/pyproject.toml b/pyproject.toml index 985a8b4c8..79c64ca42 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "olas-operate-middleware" -version = "0.1.0-rc110" +version = "0.1.0-rc111" description = "" authors = ["David Vilela ", "Viraj Patel "] readme = "README.md"