diff --git a/backend/package.json b/backend/package.json index 782ac93f..93212bfa 100644 --- a/backend/package.json +++ b/backend/package.json @@ -35,7 +35,7 @@ "@nestjs/serve-static": "^3.0.0", "@nestjs/swagger": "^5.1.1", "@nestjs/typeorm": "^8.1.0", - "@onflow/fcl": "^1.5.1", + "@onflow/fcl": "^1.6.0", "@onflow/types": "^1.0.3", "axios": "^0.21.4", "class-transformer": "0.4.0", diff --git a/frontend/package.json b/frontend/package.json index bab6a149..967ecef8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,7 +15,7 @@ "@flowser/backend": "0.0.1", "@flowser/shared": "0.0.1", "@onflow/cadence-parser": "^0.26.0", - "@onflow/fcl": "^1.5.1", + "@onflow/fcl": "^1.6.0", "@onflow/types": "^1.0.3", "@sentry/electron": "^4.0.2", "@tanstack/react-table": "^8.5.11", diff --git a/frontend/src/components/cadence-editor/cadence-editor.css b/frontend/src/components/cadence-editor/cadence-editor.css index 787fd56e..44db322e 100644 --- a/frontend/src/components/cadence-editor/cadence-editor.css +++ b/frontend/src/components/cadence-editor/cadence-editor.css @@ -1,11 +1,13 @@ /* Main editor container */ .cadence-editor { width: 100%; + height: 100%; background: #272B32; } .cadence-editor .cm-editor { background: none; + height: 100%; } .cm-focused { diff --git a/frontend/src/components/details-card/DetailsCard.module.scss b/frontend/src/components/details-card/DetailsCard.module.scss index 10c2d040..6cc91665 100644 --- a/frontend/src/components/details-card/DetailsCard.module.scss +++ b/frontend/src/components/details-card/DetailsCard.module.scss @@ -3,7 +3,6 @@ @import "styles/scrollbars"; .root { - overflow: scroll; background: $gray-100; @include hiddenScrollbars(); diff --git a/frontend/src/components/details-card/DetailsCard.tsx b/frontend/src/components/details-card/DetailsCard.tsx index fe6c2e2c..43e4585a 100644 --- a/frontend/src/components/details-card/DetailsCard.tsx +++ b/frontend/src/components/details-card/DetailsCard.tsx @@ -1,7 +1,7 @@ import classNames from "classnames"; import Label from "components/label/Label"; import Value from "components/value/Value"; -import React, { FC, ReactElement } from "react"; +import React, { CSSProperties, FC, ReactElement } from "react"; import Card from "../card/Card"; import classes from "./DetailsCard.module.scss"; import { SizedBox } from "../sized-box/SizedBox"; diff --git a/frontend/src/components/ellipsis/MiddleEllipsis.tsx b/frontend/src/components/ellipsis/MiddleEllipsis.tsx index 5b0ccf16..a30ecd48 100644 --- a/frontend/src/components/ellipsis/MiddleEllipsis.tsx +++ b/frontend/src/components/ellipsis/MiddleEllipsis.tsx @@ -2,29 +2,36 @@ import React, { FunctionComponent, useRef } from "react"; export type EllipsisProps = { children: string; - delimiter?: string; className?: string; style?: React.CSSProperties; }; const MiddleEllipsis: FunctionComponent = ({ children, - delimiter = "...", className, style, }) => { const elRef = useRef(null); - const pieceLength = 10; - const ellipsisText = - children.substring(0, pieceLength) + - delimiter + - children.substring(children.length - pieceLength, children.length); + const maxLength = 20; return ( - {ellipsisText} + {trimText(children, maxLength)} ); }; +function trimText(text: string, maxLength: number) { + const delimiter = "..."; + if (text.length <= maxLength) { + return text; + } else { + return ( + text.substring(0, maxLength / 2) + + delimiter + + text.substring(text.length - maxLength / 2, text.length) + ); + } +} + export default MiddleEllipsis; diff --git a/frontend/src/components/tabs/Tabs.module.scss b/frontend/src/components/tabs/Tabs.module.scss index 4acb0a15..1b0fc818 100644 --- a/frontend/src/components/tabs/Tabs.module.scss +++ b/frontend/src/components/tabs/Tabs.module.scss @@ -7,6 +7,7 @@ display: flex; flex-direction: column; overflow: hidden; + height: 100%; .tabWrapper { display: flex; align-items: center; diff --git a/frontend/src/contexts/ui-state.context.tsx b/frontend/src/contexts/ui-state.context.tsx index ecd071e0..1a232068 100644 --- a/frontend/src/contexts/ui-state.context.tsx +++ b/frontend/src/contexts/ui-state.context.tsx @@ -6,10 +6,9 @@ import React, { useContext, useState, } from "react"; -import { LogDrawerUiState } from "../hooks/use-log-drawer"; import { NavigationUiState } from "../hooks/use-navigation"; -export interface UiState extends LogDrawerUiState, NavigationUiState { +export interface UiState extends NavigationUiState { placeholder: { [key: string]: string }; searchTerm: { [key: string]: string }; searchDisabled: boolean; @@ -19,7 +18,6 @@ export const defaultUiState: UiState = { placeholder: { default: "Search" }, searchTerm: { default: "" }, searchDisabled: false, - logDrawerSize: "tiny", breadcrumbs: [], isBreadcrumbsVisible: false, isShowBackButtonVisible: true, diff --git a/frontend/src/hooks/use-log-drawer.ts b/frontend/src/hooks/use-log-drawer.ts deleted file mode 100644 index 4a96c8ae..00000000 --- a/frontend/src/hooks/use-log-drawer.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { UiState, useUiStateContext } from "../contexts/ui-state.context"; - -export type LogDrawerSize = "tiny" | "small" | "big" | "custom"; - -export interface LogDrawerUiState { - logDrawerSize: LogDrawerSize; -} - -export interface UseLogDrawerHook extends LogDrawerUiState { - setSize: (size: LogDrawerSize) => void; -} - -export const useLogDrawer = (): UseLogDrawerHook => { - const [state, setState] = useUiStateContext(); - - const setSize = (size: LogDrawerSize): void => { - setState((state: UiState) => ({ ...state, logDrawerSize: size })); - }; - - return { - setSize, - logDrawerSize: state.logDrawerSize, - }; -}; diff --git a/frontend/src/pages/interactions/InteractionsPage.module.scss b/frontend/src/pages/interactions/InteractionsPage.module.scss index a6c06b31..418c5e3f 100644 --- a/frontend/src/pages/interactions/InteractionsPage.module.scss +++ b/frontend/src/pages/interactions/InteractionsPage.module.scss @@ -32,15 +32,15 @@ .content { flex: 2; display: flex; + row-gap: $spacing-base; flex-direction: column; overflow: hidden; .code { - flex: 3; + height: 60%; background: #272B32; - padding-top: $spacing-base; } .details { - flex: 1; + height: 40%; background: #272B32; .error { padding: $spacing-base; diff --git a/frontend/src/pages/interactions/InteractionsPage.tsx b/frontend/src/pages/interactions/InteractionsPage.tsx index da91156e..685c75ed 100644 --- a/frontend/src/pages/interactions/InteractionsPage.tsx +++ b/frontend/src/pages/interactions/InteractionsPage.tsx @@ -93,7 +93,6 @@ function InteractionBody(): ReactElement {
-
diff --git a/frontend/src/pages/interactions/components/execution/ExecutionSettings.module.scss b/frontend/src/pages/interactions/components/execution/ExecutionSettings.module.scss index e2504ec8..7876a8cd 100644 --- a/frontend/src/pages/interactions/components/execution/ExecutionSettings.module.scss +++ b/frontend/src/pages/interactions/components/execution/ExecutionSettings.module.scss @@ -7,7 +7,12 @@ justify-content: space-between; flex-direction: column; padding: $spacing-base; - width: 300px; + min-width: 300px; + row-gap: $spacing-base; + + .top { + overflow-y: scroll; + } .bottom { display: flex; diff --git a/frontend/src/pages/interactions/components/execution/ExecutionSettings.tsx b/frontend/src/pages/interactions/components/execution/ExecutionSettings.tsx index 3c03a00c..f5b79035 100644 --- a/frontend/src/pages/interactions/components/execution/ExecutionSettings.tsx +++ b/frontend/src/pages/interactions/components/execution/ExecutionSettings.tsx @@ -22,7 +22,7 @@ import { ExternalLink } from "../../../../components/link/ExternalLink"; export function ExecutionSettings(): ReactElement { return (
-
+
diff --git a/frontend/src/pages/interactions/components/outcome/InteractionOutcome.module.scss b/frontend/src/pages/interactions/components/outcome/InteractionOutcome.module.scss index 7dc419f4..a0b21f28 100644 --- a/frontend/src/pages/interactions/components/outcome/InteractionOutcome.module.scss +++ b/frontend/src/pages/interactions/components/outcome/InteractionOutcome.module.scss @@ -8,4 +8,9 @@ padding: $spacing-base; } + .transactionOverview { + height: 100%; + padding: 0; + } + } diff --git a/frontend/src/pages/interactions/components/outcome/InteractionOutcome.tsx b/frontend/src/pages/interactions/components/outcome/InteractionOutcome.tsx index 0152e70c..4442698a 100644 --- a/frontend/src/pages/interactions/components/outcome/InteractionOutcome.tsx +++ b/frontend/src/pages/interactions/components/outcome/InteractionOutcome.tsx @@ -12,7 +12,7 @@ import { FlowScriptOutcome, FlowTransactionOutcome, } from "pages/interactions/contexts/interaction-registry.context"; -import { TabItem, Tabs } from "../../../../components/tabs/Tabs"; +import { TabItem } from "../../../../components/tabs/Tabs"; import { Callout } from "../../../../components/callout/Callout"; import { useInteractionDefinitionManager } from "../../contexts/definition.context"; import { InteractionKind } from "@flowser/shared"; @@ -125,24 +125,22 @@ function TransactionOutcome(props: { outcome: FlowTransactionOutcome }) { tabs.push({ id: overviewTabId, label: "Overview", - content: , + content: ( + + ), }); if (error) { tabs.push({ id: errorTabId, label: "Error", - content: ( - // TODO(design-revamp): Consolidate body layout styles -
- {data.transaction.status?.errorMessage ? ( - - ) : ( -
{outcome.error}
- )} -
+ content: data.transaction.status?.errorMessage ? ( + + ) : ( +
{outcome.error}
), }); } @@ -175,23 +173,13 @@ function ScriptOutcome(props: { outcome: FlowScriptOutcome }) { tabs.push({ id: errorTabId, label: "Error", - content: ( - // TODO(design-revamp): Consolidate body layout styles -
- -
- ), + content: , }); } else { tabs.push({ id: resultTabId, label: "Result", - content: ( - // TODO(design-revamp): Consolidate body layout styles -
- -
- ), + content: , }); } diff --git a/frontend/src/pages/interactions/components/templates/InteractionTemplates.module.scss b/frontend/src/pages/interactions/components/templates/InteractionTemplates.module.scss index ee4eb2e6..ab50d881 100644 --- a/frontend/src/pages/interactions/components/templates/InteractionTemplates.module.scss +++ b/frontend/src/pages/interactions/components/templates/InteractionTemplates.module.scss @@ -11,6 +11,15 @@ justify-content: space-between; position: relative; + .header { + background: $gray-100; + position: sticky; + top: 0; + padding-bottom: $spacing-base; + // Question mark icon is displayed above the header for some reason. + z-index: 1; + } + .storedTemplates { display: flex; flex-direction: column; diff --git a/frontend/src/pages/interactions/components/templates/InteractionTemplates.tsx b/frontend/src/pages/interactions/components/templates/InteractionTemplates.tsx index 33412d60..1e8720a4 100644 --- a/frontend/src/pages/interactions/components/templates/InteractionTemplates.tsx +++ b/frontend/src/pages/interactions/components/templates/InteractionTemplates.tsx @@ -39,13 +39,14 @@ function StoredTemplates() { ); return ( - <> - - +
+
+ +
{filteredAndSortedTemplates.map((template) => (
))}
- +
); } diff --git a/frontend/src/pages/interactions/hooks/use-transaction-name.ts b/frontend/src/pages/interactions/hooks/use-transaction-name.ts index 54a954ff..cfa14bfe 100644 --- a/frontend/src/pages/interactions/hooks/use-transaction-name.ts +++ b/frontend/src/pages/interactions/hooks/use-transaction-name.ts @@ -8,6 +8,7 @@ type UseInteractionNameProps = { enum TransactionKind { DEPLOY_CONTRACT, + REMOVE_CONTRACT, INITIALIZE_ACCOUNT, } @@ -20,6 +21,14 @@ const hardcodedTemplates: [string, TransactionKind][] = [ }`, TransactionKind.DEPLOY_CONTRACT, ], + [ + `transaction(name: String) { + prepare(signer: AuthAccount) { + signer.contracts.remove(name: name) + } + }`, + TransactionKind.REMOVE_CONTRACT, + ], [ `import Crypto @@ -78,6 +87,10 @@ function getDynamicName(transaction: Transaction) { return `Deploy ${ getArgumentValueById(transaction, "name") ?? "contract" }`; + case TransactionKind.REMOVE_CONTRACT: + return `Remove ${ + getArgumentValueById(transaction, "name") ?? "contract" + }`; case TransactionKind.INITIALIZE_ACCOUNT: return "Init signer account"; default: diff --git a/frontend/src/pages/logs/Logs.module.scss b/frontend/src/pages/logs/Logs.module.scss index 324ac0a0..e6dadcd8 100644 --- a/frontend/src/pages/logs/Logs.module.scss +++ b/frontend/src/pages/logs/Logs.module.scss @@ -39,7 +39,7 @@ .header { display: flex; - height: 63px; + height: 50px; color: $blue; align-items: center; overflow: hidden; diff --git a/frontend/src/pages/logs/Logs.tsx b/frontend/src/pages/logs/Logs.tsx index 65b65700..c87fdfc7 100644 --- a/frontend/src/pages/logs/Logs.tsx +++ b/frontend/src/pages/logs/Logs.tsx @@ -10,7 +10,6 @@ import classes from "./Logs.module.scss"; import { ReactComponent as ExpandIcon } from "../../assets/icons/expand.svg"; import { ReactComponent as ShrinkIcon } from "../../assets/icons/shrink.svg"; import { ReactComponent as LogsIcon } from "../../assets/icons/logs.svg"; -import { LogDrawerSize, useLogDrawer } from "../../hooks/use-log-drawer"; import CaretIcon from "../../components/caret-icon/CaretIcon"; import { useFilterData } from "../../hooks/use-filter-data"; import { useMouseMove } from "../../hooks/use-mouse-move"; @@ -28,9 +27,11 @@ type LogsProps = { className?: string; }; +type LogDrawerSize = "tiny" | "small" | "big" | "custom"; + export function Logs(props: LogsProps): ReactElement { const [trackMousePosition, setTrackMousePosition] = useState(false); - const { logDrawerSize, setSize } = useLogDrawer(); + const [logDrawerSize, setLogDrawerSize] = useState("tiny"); const tinyLogRef = useRef(null); const nonTinyLogRef = useRef(null); const logWrapperRef = logDrawerSize === "tiny" ? tinyLogRef : nonTinyLogRef; @@ -86,8 +87,8 @@ export function Logs(props: LogsProps): ReactElement { scrollToBottom(); }, [logs]); - const onCaretChange = useCallback((state) => { - if (state === false) { + const onCaretChange = useCallback((isExpanded) => { + if (isExpanded === false) { changeLogDrawerSize("small"); } else { changeLogDrawerSize("tiny"); @@ -95,7 +96,7 @@ export function Logs(props: LogsProps): ReactElement { }, []); const changeLogDrawerSize = useCallback((size: LogDrawerSize) => { - setSize(size); + setLogDrawerSize(size); setTimeout(() => { scrollToBottom(false); }, 100); @@ -107,14 +108,14 @@ export function Logs(props: LogsProps): ReactElement { const bottomPosition = window.innerHeight - mouseEvent.clientY; // collapse if user drags drawer downwards and reaches a certain threshold if (bottomPosition <= 130) { - setSize("tiny"); + setLogDrawerSize("tiny"); setTrackMousePosition(false); } }, [mouseEvent]); const startPositionDrag = useCallback(() => { setTrackMousePosition(true); - setSize("custom"); + setLogDrawerSize("custom"); }, []); const endPositionDrag = useCallback(() => { @@ -141,16 +142,7 @@ export function Logs(props: LogsProps): ReactElement { [classes.expanded]: logDrawerSize !== "tiny", })} > - { - if (logDrawerSize === "tiny") { - changeLogDrawerSize("small"); - } else { - changeLogDrawerSize("tiny"); - } - }} - > + LOGS diff --git a/frontend/src/pages/start/main/Main.tsx b/frontend/src/pages/start/main/Main.tsx index 10e04ed4..f11a5fb7 100644 --- a/frontend/src/pages/start/main/Main.tsx +++ b/frontend/src/pages/start/main/Main.tsx @@ -2,7 +2,6 @@ import React, { FunctionComponent, ReactElement, useCallback, - useEffect, useState, } from "react"; import { Link, RouteChildrenProps, useHistory } from "react-router-dom"; @@ -12,14 +11,10 @@ import longLogo from "../../../assets/images/long_logo.png"; import trash from "../../../assets/icons/trash.svg"; import newProject from "../../../assets/icons/new_project.svg"; import classes from "./Main.module.scss"; -import { - useGetAllProjects, - useGetCurrentProject, -} from "../../../hooks/use-api"; +import { useGetAllProjects } from "../../../hooks/use-api"; import { Project } from "@flowser/shared"; import classNames from "classnames"; import moment from "moment"; -import { useConfirmDialog } from "../../../contexts/confirm-dialog.context"; import { useProjectActions } from "../../../contexts/project.context"; import { SimpleButton } from "../../../components/buttons/simple-button/SimpleButton"; import { ServiceRegistry } from "../../../services/service-registry"; @@ -51,10 +46,7 @@ const tabs: ProjectTab[] = [ ]; const Main: FunctionComponent = (props) => { - const { showDialog } = useConfirmDialog(); const history = useHistory(); - const { data: currentProject, isFetching: isFetchingProject } = - useGetCurrentProject(); const providedTabId = props.location.hash?.replace("#", ""); const providedTab = tabs.find((tab) => tab.id === providedTabId); @@ -62,27 +54,10 @@ const Main: FunctionComponent = (props) => { const fallbackTab = tabs[0]; const activeTab = providedTab ?? defaultTab ?? fallbackTab; - useEffect(() => { - const isStartPage = history.location.pathname.startsWith("/start"); - const isRunningProject = Boolean(currentProject?.project); - if (isStartPage && isRunningProject && !isFetchingProject) { - history.push(routes.firstRouteAfterStart); - } - }, [history.location, currentProject]); - const onConfigure = useCallback(() => { history.push(routes.configure); }, []); - function showOpenProjectDialog() { - showDialog({ - title: "New emulator", - body: Not supported yet :(, - confirmButtonLabel: "CREATE", - cancelButtonLabel: "CANCEL", - }); - } - return (