Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 57 additions & 7 deletions apps/remix-ide-e2e/src/commands/waitForElementContainsText.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,75 @@
import { NightwatchBrowser } from 'nightwatch'
import EventEmitter from 'events'

const findElementsAsync = (browser: NightwatchBrowser, selector: string): Promise<any[]> => {
return new Promise((resolve, reject) => {
browser.findElements(selector, (result) => {
resolve(result.value as any)
})
})
}

const getTextAsync = (browser: NightwatchBrowser, elementId: string): Promise<string> => {
return new Promise((resolve, reject) => {
browser.getText(elementId, (result) => {
const text = typeof result === 'string' ? result : result.value
resolve(text as any)
})
})
}


class WaitForElementContainsText extends EventEmitter {
command (this: NightwatchBrowser, id: string, value: string, timeout = 10000): NightwatchBrowser {
let waitId // eslint-disable-line
let currentValue
const runid = setInterval(() => {
this.api.getText(id, (result) => {
currentValue = result.value
if (typeof result.value === 'string' && result.value.indexOf(value) !== -1) {
let currentValues: string[] = []
const runid = setInterval(async () => {
try {

let elements = await findElementsAsync(this.api, id)

if (!elements) {
currentValues = []
return
}

if (elements.length === 0) {
currentValues = []
return
}

// Check all elements that match the selector
let foundMatch = false
const textValues: string[] = []

for (const element of elements) {
let text = await getTextAsync(this.api, element)
currentValues.push(text)

if (typeof text === 'string' && text.indexOf(value) !== -1) {
foundMatch = true
break
}
}

currentValues = textValues

if (foundMatch) {
clearInterval(runid)
clearTimeout(waitId)
this.api.assert.ok(true, `WaitForElementContainsText ${id} contains ${value}`)
this.emit('complete')
}
})
} catch (err) {
// Ignore errors and continue polling
console.error(`Error in waitForElementContainsText for selector ${id}:`, err)
}
}, 200)

waitId = setTimeout(() => {
clearInterval(runid)
this.api.assert.fail(`TimeoutError: An error occurred while running .waitForElementContainsText() command on ${id} after ${timeout} milliseconds. expected: ${value} - got: ${currentValue}`)
const valuesFound = currentValues.length > 0 ? currentValues.join(', ') : 'none'
this.api.assert.fail(`TimeoutError: An error occurred while running .waitForElementContainsText() command on ${id} after ${timeout} milliseconds. expected: ${value} - got: ${valuesFound}`)
}, timeout)
return this
}
Expand Down
20 changes: 15 additions & 5 deletions apps/remix-ide/src/app/plugins/notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,31 @@ import { LibraryProfile, MethodApi, StatusEvents } from '@remixproject/plugin-ut
import { AppModal } from '@remix-ui/app'
import { AlertModal } from '@remix-ui/app'
import { dispatchModalInterface } from '@remix-ui/app'
import { Toaster, toast } from '@remix-ui/toaster'

interface INotificationApi {
events: StatusEvents
methods: {
modal: (args: AppModal) => void
alert: (args: AlertModal) => void
toast: (message: string) => void

toast: (message: string) => number
hideToaster: (id: number) => void
}
}

const profile: LibraryProfile<INotificationApi> = {
name: 'notification',
displayName: 'Notification',
description: 'Displays notifications',
methods: ['modal', 'alert', 'toast']
methods: ['modal', 'alert', 'toast', 'hideToaster']
}

export class NotificationPlugin extends Plugin implements MethodApi<INotificationApi> {
dispatcher: dispatchModalInterface
toastId: number
constructor() {
super(profile)
this.toastId = 0
}

setDispatcher(dispatcher: dispatchModalInterface) {
Expand All @@ -40,7 +43,14 @@ export class NotificationPlugin extends Plugin implements MethodApi<INotificatio
return this.dispatcher.alert(args)
}

async toast(message: string | JSX.Element) {
this.dispatcher.toast(message)
async toast(message: string | JSX.Element, timeout?: number, timestamp?: number): Promise<number> {
timestamp = timestamp || Date.now()
timestamp = timestamp + ++this.toastId
this.dispatcher.toast(message, timeout, timestamp)
return timestamp
}

async hideToaster(id: number) {
toast.dismiss('toast-' + id)
}
}
6 changes: 3 additions & 3 deletions apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css
Original file line number Diff line number Diff line change
Expand Up @@ -5596,14 +5596,14 @@ textarea.form-control-lg {
--bs-toast-spacing: 1.5rem;
--bs-toast-max-width: 350px;
--bs-toast-font-size: 0.875rem;
--bs-toast-color: ;
--bs-toast-bg: #444;
--bs-toast-color: var(--bs-body-color);
--bs-toast-bg: var(--bs-light);
--bs-toast-border-width: var(--bs-border-width);
--bs-toast-border-color: var(--bs-border-color-translucent);
--bs-toast-border-radius: var(--bs-border-radius);
--bs-toast-box-shadow: var(--bs-box-shadow);
--bs-toast-header-color: var(--bs-secondary-color);
--bs-toast-header-bg: #303030;
--bs-toast-header-bg: var(--bs-body-bg);
--bs-toast-header-border-color: var(--bs-border-color-translucent);
width: var(--bs-toast-max-width);
max-width: 100%;
Expand Down
6 changes: 3 additions & 3 deletions apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css
Original file line number Diff line number Diff line change
Expand Up @@ -5598,14 +5598,14 @@ textarea.form-control-lg {
--bs-toast-spacing: 1.5rem;
--bs-toast-max-width: 350px;
--bs-toast-font-size: 0.875rem;
--bs-toast-color: ;
--bs-toast-bg: rgba(var(--bs-body-bg-rgb), 0.85);
--bs-toast-color: var(--bs-body-color);
--bs-toast-bg: var(--bs-light);
--bs-toast-border-width: var(--bs-border-width);
--bs-toast-border-color: var(--bs-border-color-translucent);
--bs-toast-border-radius: var(--bs-border-radius);
--bs-toast-box-shadow: var(--bs-box-shadow);
--bs-toast-header-color: var(--bs-secondary-color);
--bs-toast-header-bg: rgba(var(--bs-body-bg-rgb), 0.85);
--bs-toast-header-bg: var(--bs-body-bg);
--bs-toast-header-border-color: var(--bs-border-color-translucent);
width: var(--bs-toast-max-width);
max-width: 100%;
Expand Down
2 changes: 1 addition & 1 deletion libs/remix-ui/app/src/lib/remix-app/actions/modals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const enum modalActionTypes {
type ModalPayload = {
[modalActionTypes.setModal]: AppModal
[modalActionTypes.handleHideModal]: any
[modalActionTypes.setToast]: { message: string | JSX.Element, timestamp: number }
[modalActionTypes.setToast]: { message: string | JSX.Element, timestamp: number, timeout?: number }
[modalActionTypes.handleToaster]: any,
[modalActionTypes.processQueue]: any,
[modalActionTypes.setTemplateExplorer]: GenericModal
Expand Down
19 changes: 15 additions & 4 deletions libs/remix-ui/app/src/lib/remix-app/components/modals/dialogs.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import React from 'react'
import React, { useMemo } from 'react'
import { useDialogDispatchers, useDialogs } from '../../context/provider'
import { Toaster } from '@remix-ui/toaster'
import { ToasterContainer } from '@remix-ui/toaster'
import ModalWrapper from './modal-wrapper'

const AppDialogs = () => {
const { handleHideModal, handleToaster } = useDialogDispatchers()
const { focusModal, focusToaster } = useDialogs()
const { focusModal, toasters } = useDialogs()

// Map toasters to ToasterProps format with useMemo to prevent recreating on every render
const toastList = useMemo(() => {
return toasters.map((toaster) => ({
message: toaster.message,
id: toaster.toastId || `toast-${toaster.timestamp}`,
timeout: toaster.timeout,
timestamp: toaster.timestamp,
handleHide: handleToaster
}))
}, [toasters, handleToaster])

return (
<>
<ModalWrapper {...focusModal} handleHide={handleHideModal}></ModalWrapper>
<Toaster message={focusToaster.message} timestamp={focusToaster.timestamp} handleHide={handleToaster} />
<ToasterContainer toasts={toastList} />
</>
)
}
Expand Down
4 changes: 2 additions & 2 deletions libs/remix-ui/app/src/lib/remix-app/context/context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ export const platformContext = React.createContext<appPlatformTypes>(null)

export interface dispatchModalInterface {
modal: (data: AppModal) => void
toast: (message: string | JSX.Element) => void
toast: (message: string | JSX.Element, timeout?: number, toastId?: number) => void
alert: (data: AlertModal) => void
handleHideModal: () => void
handleToaster: () => void
}

export const dispatchModalContext = React.createContext<dispatchModalInterface>({
modal: (data: AppModal) => {},
toast: (message: string | JSX.Element) => {},
toast: (message: string | JSX.Element, timeout?: number, toastId?: number) => {},
alert: (data: AlertModal) => {},
handleHideModal: () => {},
handleToaster: () => {}
Expand Down
5 changes: 3 additions & 2 deletions libs/remix-ui/app/src/lib/remix-app/context/provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ export const ModalProvider = ({ children = [], reducer = modalReducer, initialSt
})
}

const toast = (message: string | JSX.Element) => {
const toast = (message: string | JSX.Element, timeout?: number, timestamp?: number) => {
timestamp = timestamp || Date.now()
dispatch({
type: modalActionTypes.setToast,
payload: { message, timestamp: Date.now() }
payload: { message, timestamp, timeout }
})
}

Expand Down
4 changes: 2 additions & 2 deletions libs/remix-ui/app/src/lib/remix-app/interface/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export interface AlertModal {

export interface ModalState {
modals: AppModal[],
toasters: {message: (string | JSX.Element), timestamp: number }[],
toasters: {message: (string | JSX.Element), timestamp: number, timeout?: number, toastId?: number }[],
focusModal: AppModal,
focusToaster: {message: (string | JSX.Element), timestamp: number },
focusToaster: {message: (string | JSX.Element), timestamp: number, timeout?: number, toastId?: number }
focusTemplateExplorer: GenericModal
}

Expand Down
2 changes: 1 addition & 1 deletion libs/remix-ui/app/src/lib/remix-app/state/modals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const ModalInitialState: ModalState = {
cancelFn: () => { },
showCancelIcon: false
},
focusToaster: { message: '', timestamp: 0 },
focusToaster: { message: '', timestamp: 0, timeout: 2000 },
focusTemplateExplorer: {
id: '',
hide: true,
Expand Down
Loading