Skip to content

Commit 5725363

Browse files
author
ci-bot
committed
Merge remote-tracking branch 'origin/master' into feat/nx-cloud/setup
2 parents 506d889 + 119877a commit 5725363

File tree

9 files changed

+122
-36
lines changed

9 files changed

+122
-36
lines changed

apps/remix-ide-e2e/src/tests/dgit_github.test.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ module.exports = {
4444
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]')
4545
.waitForElementVisible('*[data-id="remotes-panel"]')
4646
},
47+
'check the FE shows logged in user #group1 #group2': function (browser: NightwatchBrowser) {
48+
browser
49+
.waitForElementVisible({
50+
selector: '//*[@data-id="github-dropdown-toggle-login"]//span[contains(text(), "bunsenstraat")]',
51+
locateStrategy: 'xpath'
52+
})
53+
},
4754
// 'check the FE for the auth user #group1 #group2': function (browser: NightwatchBrowser) {
4855
// browser
4956
// .clickLaunchIcon('filePanel')
@@ -213,16 +220,39 @@ module.exports = {
213220
locateStrategy: 'xpath'
214221
})
215222
},
216-
'disconnect github #group1': function (browser: NightwatchBrowser) {
223+
'reload page and check login persistence #group1': function (browser: NightwatchBrowser) {
217224
browser
225+
.refresh()
226+
.pause(5000) // Wait for page to fully reload
227+
.waitForElementVisible('*[data-id="remixIdeIconPanel"]', 10000)
228+
.clickLaunchIcon('dgit')
218229
.waitForElementVisible('*[data-id="github-panel"]')
219-
.pause(1000)
220230
.click('*[data-id="github-panel"]')
231+
.waitForElementVisible('*[data-id="connected-as-bunsenstraat"]')
232+
.waitForElementVisible('*[data-id="connected-img-bunsenstraat"]')
233+
.waitForElementVisible('*[data-id="connected-link-bunsenstraat"]')
234+
},
235+
'check the FE shows logged in user after reload #group1': function (browser: NightwatchBrowser) {
236+
browser
237+
.waitForElementVisible({
238+
selector: '//*[@data-id="github-dropdown-toggle-login"]//span[contains(text(), "bunsenstraat")]',
239+
locateStrategy: 'xpath'
240+
})
241+
},
242+
'disconnect github #group1': function (browser: NightwatchBrowser) {
243+
browser
221244
.waitForElementVisible('*[data-id="disconnect-github"]')
222245
.pause(1000)
223246
.click('*[data-id="disconnect-github"]')
224247
.waitForElementNotPresent('*[data-id="connected-as-bunsenstraat"]')
225248
},
249+
'check the FE for the disconnected auth user #group1': function (browser: NightwatchBrowser) {
250+
browser
251+
.waitForElementNotPresent({
252+
selector: '//*[@data-id="github-dropdown-toggle-login"]//span[contains(text(), "bunsenstraat")]',
253+
locateStrategy: 'xpath'
254+
})
255+
},
226256
// 'check the FE for the disconnected auth user #group1': function (browser: NightwatchBrowser) {
227257
// browser
228258
// .clickLaunchIcon('filePanel')

apps/remix-ide/ci/deploy_remix-live.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ git checkout -b gh-pages
1414
git config user.name "$COMMIT_AUTHOR"
1515
git config user.email "$COMMIT_AUTHOR_EMAIL"
1616

17+
echo "remix.ethereum.org" > CNAME
18+
1719
echo "# Automatic build" > README.md
1820
echo "Built website from \`$SHA\`. See https://github.com/remix-project-org/remix-project/ for details." >> README.md
1921
echo "To use an offline copy, download \`remix-$SHA.zip\`." >> README.md

libs/remix-api/src/lib/plugins/matomo/events/file-events.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ export interface WorkspaceEvent extends MatomoEventBase {
2424
category: 'Workspace';
2525
action:
2626
| 'switchWorkspace'
27-
| 'GIT'
28-
| 'createWorkspace';
27+
| 'template'
28+
| 'GIT';
2929
}
3030

3131
export interface StorageEvent extends MatomoEventBase {

libs/remix-ui/git/src/lib/listeners.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ export const setCallBacks = (viewPlugin: Plugin, gitDispatcher: React.Dispatch<g
4747
// Initialize the login plugin reference
4848
setLoginPlugin(viewPlugin)
4949

50+
plugin.call('manager', 'isActive', 'dgitApi').then( (isActive) => {
51+
if (isActive) {
52+
loadGitHubUserFromToken();
53+
}
54+
});
55+
5056
plugin.on("fileManager", "fileSaved", async (file: string) => {
5157
loadFileQueue.enqueue(async () => {
5258
loadFiles()

libs/remix-ui/remix-ai-assistant/src/components/remix-ui-remix-ai-assistant.tsx

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ export const RemixUiRemixAiAssistant = React.forwardRef<
6464
const contextBtnRef = useRef(null)
6565
const textareaRef = useRef<HTMLTextAreaElement>(null)
6666
const aiChatRef = useRef<HTMLDivElement>(null)
67+
const userHasScrolledRef = useRef(false)
68+
const lastMessageCountRef = useRef(0)
6769

6870
useOnClickOutside([modelBtnRef, contextBtnRef], () => setShowAssistantOptions(false))
6971
useOnClickOutside([modelBtnRef, contextBtnRef], () => setShowContextOptions(false))
@@ -224,13 +226,25 @@ export const RemixUiRemixAiAssistant = React.forwardRef<
224226
props.onMessagesChange?.(messages)
225227
}, [messages, props.onMessagesChange])
226228

227-
// always scroll to bottom when messages change
229+
// Smart auto-scroll: only scroll to bottom if:
228230
useEffect(() => {
229231
const node = historyRef.current
230-
if (node && messages.length > 0) {
232+
if (!node || messages.length === 0) return
233+
234+
const isAtBottom = node.scrollHeight - node.scrollTop - node.clientHeight < 100
235+
const userSentNewMessage = messages.length > lastMessageCountRef.current &&
236+
messages[messages.length - 1]?.role === 'user'
237+
// Auto-scroll conditions:
238+
// - User sent a new message (always scroll)
239+
// - User hasn't manually scrolled up (userHasScrolledRef is false)
240+
// - Currently streaming and user is near bottom
241+
if (userSentNewMessage || !userHasScrolledRef.current || (isStreaming && isAtBottom)) {
231242
node.scrollTop = node.scrollHeight
243+
userHasScrolledRef.current = false
232244
}
233-
}, [messages])
245+
246+
lastMessageCountRef.current = messages.length
247+
}, [messages, isStreaming])
234248

235249
useEffect(() => {
236250
if (textareaRef.current) {
@@ -662,11 +676,24 @@ export const RemixUiRemixAiAssistant = React.forwardRef<
662676
)
663677
const chatHistoryRef = useRef<HTMLElement | null>(null)
664678

679+
// Detect manual user scrolling
665680
useEffect(() => {
666-
if (chatHistoryRef.current) {
667-
chatHistoryRef.current.scrollTop = chatHistoryRef.current.scrollHeight
681+
const node = historyRef.current
682+
if (!node) return
683+
684+
const handleScroll = () => {
685+
const isAtBottom = node.scrollHeight - node.scrollTop - node.clientHeight < 100
686+
687+
if (!isAtBottom) {
688+
userHasScrolledRef.current = true
689+
} else {
690+
userHasScrolledRef.current = false
691+
}
668692
}
669-
}, [messages])
693+
694+
node.addEventListener('scroll', handleScroll)
695+
return () => node.removeEventListener('scroll', handleScroll)
696+
}, [])
670697

671698
const maximizePanel = async () => {
672699
await props.plugin.call('layout', 'maximisePinnedPanel')

libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,13 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
415415
evmVersion = JSON.parse(loadedContractData.metadata).settings.evmVersion
416416
}
417417
} catch (err) {}
418+
419+
const deployButtonTitle = isVerifyChecked
420+
? intl.formatMessage({ id: 'udapp.deployAndVerify', defaultMessage: 'Deploy & Verify' })
421+
: intl.formatMessage({ id: 'udapp.deploy' })
422+
423+
const deployButtonWidthClass = isVerifyChecked ? 'w-auto' : 'w-50'
424+
418425
return (
419426
<div className="udapp_container mb-2" data-id="contractDropdownContainer">
420427
<div className="d-flex justify-content-between">
@@ -492,7 +499,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
492499
</span>
493500
}
494501
>
495-
<span className="udapp_evmVersion badge alert-warning">
502+
<span className="udapp_evmVersion badge alert-warning mb-2">
496503
<FormattedMessage id="udapp.evmVersion" />: {evmVersion}
497504
</span>
498505
</CustomTooltip>
@@ -501,8 +508,14 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
501508
<div className="udapp_deployDropdown">
502509
{((contractList[currentFile] && contractList[currentFile].filter((contract) => contract)) || []).length > 0 && loadedContractData && (
503510
<div>
511+
{isNetworkSupported && (
512+
<VerificationSettingsUI
513+
isVerifyChecked={isVerifyChecked}
514+
onVerifyCheckedChange={handleVerifyCheckedChange}
515+
/>
516+
)}
504517
<ContractGUI
505-
title={intl.formatMessage({ id: 'udapp.deploy' })}
518+
title={deployButtonTitle}
506519
getCompilerDetails={props.getCompilerDetails}
507520
isDeploy={true}
508521
deployOption={deployOptions[currentFile] && deployOptions[currentFile][currentContract] ? deployOptions[currentFile][currentContract].options : null}
@@ -512,7 +525,7 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
512525
funcABI={constructorInterface}
513526
clickCallBack={clickCallback}
514527
inputs={constructorInputs}
515-
widthClass="w-50"
528+
widthClass={deployButtonWidthClass}
516529
evmBC={loadedContractData.bytecodeObject}
517530
lookupOnly={false}
518531
proxy={props.proxy}
@@ -528,12 +541,6 @@ export function ContractDropdownUI(props: ContractDropdownProps) {
528541
plugin={props.plugin}
529542
runTabState={props.runTabState}
530543
/>
531-
{isNetworkSupported && (
532-
<VerificationSettingsUI
533-
isVerifyChecked={isVerifyChecked}
534-
onVerifyCheckedChange={handleVerifyCheckedChange}
535-
/>
536-
)}
537544
</div>
538545
)}
539546
</div>

libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export function ContractGUI(props: ContractGUIProps) {
3232
const multiFields = useRef<Array<HTMLInputElement | null>>([])
3333
const initializeFields = useRef<Array<HTMLInputElement | null>>([])
3434
const basicInputRef = useRef<HTMLInputElement>()
35+
const [baseTitleForDataId, setBaseTitleForDataId] = useState<string>('')
3536

3637
const intl = useIntl()
3738
useEffect(() => {
@@ -42,19 +43,34 @@ export function ContractGUI(props: ContractGUIProps) {
4243
}, [props.deployOption])
4344

4445
useEffect(() => {
46+
let newTitle = ''
47+
let newBaseTitle = ''
48+
4549
if (props.title) {
46-
setTitle(props.title)
50+
newTitle = props.title
4751
} else if (props.funcABI.name) {
48-
setTitle(props.funcABI.name)
52+
newTitle = props.funcABI.name
4953
} else {
50-
setTitle(props.funcABI.type === 'receive' ? '(receive)' : '(fallback)')
54+
newTitle = props.funcABI.type === 'receive' ? '(receive)' : '(fallback)'
5155
}
56+
57+
if (props.isDeploy) {
58+
newBaseTitle = intl.formatMessage({ id: 'udapp.deploy', defaultMessage: 'Deploy' })
59+
} else if (props.funcABI.name) {
60+
newBaseTitle = props.funcABI.name
61+
} else {
62+
newBaseTitle = props.funcABI.type === 'receive' ? '(receive)' : '(fallback)'
63+
}
64+
65+
setTitle(newTitle)
66+
setBaseTitleForDataId(newBaseTitle)
67+
5268
setBasicInput('')
5369
// we have the reset the fields before resetting the previous references.
5470
basicInputRef.current.value = ''
5571
multiFields.current.filter((el) => el !== null && el !== undefined).forEach((el) => (el.value = ''))
5672
multiFields.current = []
57-
}, [props.title, props.funcABI])
73+
}, [props.title, props.funcABI, props.isDeploy, intl])
5874

5975
useEffect(() => {
6076
if (props.lookupOnly) {
@@ -63,26 +79,26 @@ export function ContractGUI(props: ContractGUIProps) {
6379
title: title + ' - call',
6480
content: 'call',
6581
classList: 'btn-primary',
66-
dataId: title + ' - call'
82+
dataId: baseTitleForDataId + ' - call'
6783
})
6884
} else if (props.funcABI.stateMutability === 'payable' || props.funcABI.payable) {
6985
// // transact. stateMutability = payable
7086
setButtonOptions({
7187
title: title + ' - transact (payable)',
7288
content: 'transact',
7389
classList: 'btn-danger',
74-
dataId: title + ' - transact (payable)'
90+
dataId: baseTitleForDataId + ' - transact (payable)'
7591
})
7692
} else {
7793
// // transact. stateMutability = nonpayable
7894
setButtonOptions({
7995
title: title + ' - transact (not payable)',
8096
content: 'transact',
8197
classList: 'btn-warning',
82-
dataId: title + ' - transact (not payable)'
98+
dataId: baseTitleForDataId + ' - transact (not payable)'
8399
})
84100
}
85-
}, [props.lookupOnly, props.funcABI, title])
101+
}, [props.lookupOnly, props.funcABI, title, baseTitleForDataId])
86102

87103
const getEncodedCall = () => {
88104
const multiString = getMultiValsString(multiFields.current)

libs/remix-ui/top-bar/src/lib/remix-ui-topbar.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ export function RemixUiTopbar() {
292292

293293
const loginWithGitHub = async () => {
294294
global.plugin.call('dgit', 'login')
295-
trackMatomoEvent({ category: 'topbar', action: 'header', name: 'Settings', isClick: true })
295+
trackMatomoEvent({ category: 'topbar', action: 'GIT', name: 'login', isClick: true })
296296
}
297297

298298
const logOutOfGithub = async () => {

libs/remix-ui/workspace/src/lib/actions/workspace.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,10 @@ export const populateWorkspace = async (
239239
if (workspaceTemplateName === 'semaphore' || workspaceTemplateName === 'hashchecker' || workspaceTemplateName === 'rln') {
240240
const isCircomActive = await plugin.call('manager', 'isActive', 'circuit-compiler')
241241
if (!isCircomActive) await plugin.call('manager', 'activatePlugin', 'circuit-compiler')
242-
await trackMatomoEventAsync(plugin, { category: 'compiler', action: 'compiled', name: workspaceTemplateName, isClick: false })
243242
}
244243
if (workspaceTemplateName === 'multNr' || workspaceTemplateName === 'stealthDropNr') {
245244
const isNoirActive = await plugin.call('manager', 'isActive', 'noir-compiler')
246245
if (!isNoirActive) await plugin.call('manager', 'activatePlugin', 'noir-compiler')
247-
await trackMatomoEventAsync(plugin, { category: 'compiler', action: 'compiled', name: workspaceTemplateName, isClick: false })
248246
}
249247
}
250248

@@ -301,15 +299,15 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
301299
let content
302300

303301
if (params.code) {
304-
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'switchWorkspace', name: 'code-template-code-param', isClick: false })
302+
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-code-param', isClick: false })
305303
const hashed = bytesToHex(hash.keccakFromString(params.code))
306304

307305
path = 'contract-' + hashed.replace('0x', '').substring(0, 10) + (params.language && params.language.toLowerCase() === 'yul' ? '.yul' : '.sol')
308306
content = decodePercentEscapedBase64(params.code)
309307
await workspaceProvider.set(path, content)
310308
}
311309
if (params.shareCode) {
312-
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'switchWorkspace', name: 'code-template-shareCode-param', isClick: false })
310+
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-shareCode-param', isClick: false })
313311
const host = '127.0.0.1'
314312
const port = 5001
315313
const protocol = 'http'
@@ -334,7 +332,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
334332
await workspaceProvider.set(path, content)
335333
}
336334
if (params.url) {
337-
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'switchWorkspace', name: 'code-template-url-param', isClick: false })
335+
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-url-param', isClick: false })
338336
const data = await plugin.call('contentImport', 'resolve', params.url)
339337
path = data.cleanUrl
340338
content = data.content
@@ -358,7 +356,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
358356
}
359357
if (params.ghfolder) {
360358
try {
361-
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'switchWorkspace', name: 'code-template-ghfolder-param', isClick: false })
359+
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'code-template-ghfolder-param', isClick: false })
362360
const files = await plugin.call('contentImport', 'resolveGithubFolder', params.ghfolder)
363361
for (const [path, content] of Object.entries(files)) {
364362
await workspaceProvider.set(path, content)
@@ -377,7 +375,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
377375
case 'gist-template':
378376
// creates a new workspace gist-sample and get the file from gist
379377
try {
380-
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'switchWorkspace', name: 'gist-template', isClick: false })
378+
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: 'gist-template', isClick: false })
381379
const gistId = params.gist
382380
const response: AxiosResponse = await axios.get(`https://api.github.com/gists/${gistId}`)
383381
const data = response.data as { files: any }
@@ -440,7 +438,7 @@ export const loadWorkspacePreset = async (template: WorkspaceTemplate = 'remixDe
440438
const templateList = Object.keys(templateWithContent)
441439
if (!templateList.includes(template)) break
442440

443-
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'switchWorkspace', name: template, isClick: false })
441+
await trackMatomoEventAsync(plugin, { category: 'Workspace', action: 'template', name: template, isClick: false })
444442
// @ts-ignore
445443
const files = await templateWithContent[template](opts, plugin)
446444
for (const file in files) {

0 commit comments

Comments
 (0)