mirror of
https://github.com/stackblitz-labs/bolt.diy
synced 2025-03-09 13:41:00 +00:00
[UX] click shortcut in chat to go to source file in workbench
This commit is contained in:
parent
233d22e080
commit
d419a3c4b5
@ -7,6 +7,7 @@ import type { ActionState } from '~/lib/runtime/action-runner';
|
|||||||
import { workbenchStore } from '~/lib/stores/workbench';
|
import { workbenchStore } from '~/lib/stores/workbench';
|
||||||
import { classNames } from '~/utils/classNames';
|
import { classNames } from '~/utils/classNames';
|
||||||
import { cubicEasingFn } from '~/utils/easings';
|
import { cubicEasingFn } from '~/utils/easings';
|
||||||
|
import { WORK_DIR } from '~/utils/constants';
|
||||||
|
|
||||||
const highlighterOptions = {
|
const highlighterOptions = {
|
||||||
langs: ['shell'],
|
langs: ['shell'],
|
||||||
@ -129,6 +130,14 @@ const actionVariants = {
|
|||||||
visible: { opacity: 1, y: 0 },
|
visible: { opacity: 1, y: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function openArtifactInWorkbench(filePath: any) {
|
||||||
|
if (workbenchStore.currentView.get() !== 'code') {
|
||||||
|
workbenchStore.currentView.set('code');
|
||||||
|
}
|
||||||
|
|
||||||
|
workbenchStore.setSelectedFile(`${WORK_DIR}/${filePath}`);
|
||||||
|
}
|
||||||
|
|
||||||
const ActionList = memo(({ actions }: ActionListProps) => {
|
const ActionList = memo(({ actions }: ActionListProps) => {
|
||||||
return (
|
return (
|
||||||
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.15 }}>
|
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} transition={{ duration: 0.15 }}>
|
||||||
@ -169,7 +178,10 @@ const ActionList = memo(({ actions }: ActionListProps) => {
|
|||||||
{type === 'file' ? (
|
{type === 'file' ? (
|
||||||
<div>
|
<div>
|
||||||
Create{' '}
|
Create{' '}
|
||||||
<code className="bg-bolt-elements-artifacts-inlineCode-background text-bolt-elements-artifacts-inlineCode-text px-1.5 py-1 rounded-md">
|
<code
|
||||||
|
className="bg-bolt-elements-artifacts-inlineCode-background text-bolt-elements-artifacts-inlineCode-text px-1.5 py-1 rounded-md text-bolt-elements-item-contentAccent hover:underline cursor-pointer"
|
||||||
|
onClick={() => openArtifactInWorkbench(action.filePath)}
|
||||||
|
>
|
||||||
{action.filePath}
|
{action.filePath}
|
||||||
</code>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
|
@ -180,8 +180,8 @@ export const Workbench = memo(({ chatStarted, isStreaming }: WorkspaceProps) =>
|
|||||||
alert("GitHub token is required. Push to GitHub cancelled.");
|
alert("GitHub token is required. Push to GitHub cancelled.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
workbenchStore.pushToGitHub(repoName, githubUsername, githubToken);
|
workbenchStore.pushToGitHub(repoName, githubUsername, githubToken);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="i-ph:github-logo" />
|
<div className="i-ph:github-logo" />
|
||||||
|
@ -39,20 +39,20 @@ You are Bolt, an expert AI assistant and exceptional senior software developer w
|
|||||||
- rm: Remove files
|
- rm: Remove files
|
||||||
- rmdir: Remove empty directories
|
- rmdir: Remove empty directories
|
||||||
- touch: Create empty file/update timestamp
|
- touch: Create empty file/update timestamp
|
||||||
|
|
||||||
System Information:
|
System Information:
|
||||||
- hostname: Show system name
|
- hostname: Show system name
|
||||||
- ps: Display running processes
|
- ps: Display running processes
|
||||||
- pwd: Print working directory
|
- pwd: Print working directory
|
||||||
- uptime: Show system uptime
|
- uptime: Show system uptime
|
||||||
- env: Environment variables
|
- env: Environment variables
|
||||||
|
|
||||||
Development Tools:
|
Development Tools:
|
||||||
- node: Execute Node.js code
|
- node: Execute Node.js code
|
||||||
- python3: Run Python scripts
|
- python3: Run Python scripts
|
||||||
- code: VSCode operations
|
- code: VSCode operations
|
||||||
- jq: Process JSON
|
- jq: Process JSON
|
||||||
|
|
||||||
Other Utilities:
|
Other Utilities:
|
||||||
- curl, head, sort, tail, clear, which, export, chmod, scho, hostname, kill, ln, xxd, alias, false, getconf, true, loadenv, wasm, xdg-open, command, exit, source
|
- curl, head, sort, tail, clear, which, export, chmod, scho, hostname, kill, ln, xxd, alias, false, getconf, true, loadenv, wasm, xdg-open, command, exit, source
|
||||||
</system_constraints>
|
</system_constraints>
|
||||||
@ -88,7 +88,7 @@ You are Bolt, an expert AI assistant and exceptional senior software developer w
|
|||||||
Example:
|
Example:
|
||||||
|
|
||||||
<${MODIFICATIONS_TAG_NAME}>
|
<${MODIFICATIONS_TAG_NAME}>
|
||||||
<diff path="/home/project/src/main.js">
|
<diff path="${WORK_DIR}/src/main.js">
|
||||||
@@ -2,7 +2,10 @@
|
@@ -2,7 +2,10 @@
|
||||||
return a + b;
|
return a + b;
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ You are Bolt, an expert AI assistant and exceptional senior software developer w
|
|||||||
+
|
+
|
||||||
+console.log('The End');
|
+console.log('The End');
|
||||||
</diff>
|
</diff>
|
||||||
<file path="/home/project/package.json">
|
<file path="${WORK_DIR}/package.json">
|
||||||
// full file content here
|
// full file content here
|
||||||
</file>
|
</file>
|
||||||
</${MODIFICATIONS_TAG_NAME}>
|
</${MODIFICATIONS_TAG_NAME}>
|
||||||
@ -124,7 +124,7 @@ You are Bolt, an expert AI assistant and exceptional senior software developer w
|
|||||||
2. Create TodoList and TodoItem components
|
2. Create TodoList and TodoItem components
|
||||||
3. Implement localStorage for persistence
|
3. Implement localStorage for persistence
|
||||||
4. Add CRUD operations
|
4. Add CRUD operations
|
||||||
|
|
||||||
Let's start now.
|
Let's start now.
|
||||||
|
|
||||||
[Rest of response...]"
|
[Rest of response...]"
|
||||||
@ -134,7 +134,7 @@ You are Bolt, an expert AI assistant and exceptional senior software developer w
|
|||||||
1. Check network requests
|
1. Check network requests
|
||||||
2. Verify API endpoint format
|
2. Verify API endpoint format
|
||||||
3. Examine error handling
|
3. Examine error handling
|
||||||
|
|
||||||
[Rest of response...]"
|
[Rest of response...]"
|
||||||
|
|
||||||
</chain_of_thought_instructions>
|
</chain_of_thought_instructions>
|
||||||
|
@ -14,6 +14,7 @@ import { saveAs } from 'file-saver';
|
|||||||
import { Octokit, type RestEndpointMethodTypes } from "@octokit/rest";
|
import { Octokit, type RestEndpointMethodTypes } from "@octokit/rest";
|
||||||
import * as nodePath from 'node:path';
|
import * as nodePath from 'node:path';
|
||||||
import type { WebContainerProcess } from '@webcontainer/api';
|
import type { WebContainerProcess } from '@webcontainer/api';
|
||||||
|
import { extractRelativePath } from '~/utils/diff';
|
||||||
|
|
||||||
export interface ArtifactState {
|
export interface ArtifactState {
|
||||||
id: string;
|
id: string;
|
||||||
@ -312,8 +313,7 @@ export class WorkbenchStore {
|
|||||||
|
|
||||||
for (const [filePath, dirent] of Object.entries(files)) {
|
for (const [filePath, dirent] of Object.entries(files)) {
|
||||||
if (dirent?.type === 'file' && !dirent.isBinary) {
|
if (dirent?.type === 'file' && !dirent.isBinary) {
|
||||||
// remove '/home/project/' from the beginning of the path
|
const relativePath = extractRelativePath(filePath);
|
||||||
const relativePath = filePath.replace(/^\/home\/project\//, '');
|
|
||||||
|
|
||||||
// split the path into segments
|
// split the path into segments
|
||||||
const pathSegments = relativePath.split('/');
|
const pathSegments = relativePath.split('/');
|
||||||
@ -343,7 +343,7 @@ export class WorkbenchStore {
|
|||||||
|
|
||||||
for (const [filePath, dirent] of Object.entries(files)) {
|
for (const [filePath, dirent] of Object.entries(files)) {
|
||||||
if (dirent?.type === 'file' && !dirent.isBinary) {
|
if (dirent?.type === 'file' && !dirent.isBinary) {
|
||||||
const relativePath = filePath.replace(/^\/home\/project\//, '');
|
const relativePath = extractRelativePath(filePath);
|
||||||
const pathSegments = relativePath.split('/');
|
const pathSegments = relativePath.split('/');
|
||||||
let currentHandle = targetHandle;
|
let currentHandle = targetHandle;
|
||||||
|
|
||||||
@ -417,7 +417,7 @@ export class WorkbenchStore {
|
|||||||
content: Buffer.from(dirent.content).toString('base64'),
|
content: Buffer.from(dirent.content).toString('base64'),
|
||||||
encoding: 'base64',
|
encoding: 'base64',
|
||||||
});
|
});
|
||||||
return { path: filePath.replace(/^\/home\/project\//, ''), sha: blob.sha };
|
return { path: extractRelativePath(filePath), sha: blob.sha };
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
11
app/utils/diff.spec.ts
Normal file
11
app/utils/diff.spec.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import { extractRelativePath } from './diff';
|
||||||
|
import { WORK_DIR } from './constants';
|
||||||
|
|
||||||
|
describe('Diff', () => {
|
||||||
|
it('should strip out Work_dir', () => {
|
||||||
|
const filePath = `${WORK_DIR}/index.js`;
|
||||||
|
const result = extractRelativePath(filePath);
|
||||||
|
expect(result).toBe('index.js');
|
||||||
|
});
|
||||||
|
});
|
@ -1,6 +1,6 @@
|
|||||||
import { createTwoFilesPatch } from 'diff';
|
import { createTwoFilesPatch } from 'diff';
|
||||||
import type { FileMap } from '~/lib/stores/files';
|
import type { FileMap } from '~/lib/stores/files';
|
||||||
import { MODIFICATIONS_TAG_NAME } from './constants';
|
import { MODIFICATIONS_TAG_NAME, WORK_DIR } from './constants';
|
||||||
|
|
||||||
export const modificationsRegex = new RegExp(
|
export const modificationsRegex = new RegExp(
|
||||||
`^<${MODIFICATIONS_TAG_NAME}>[\\s\\S]*?<\\/${MODIFICATIONS_TAG_NAME}>\\s+`,
|
`^<${MODIFICATIONS_TAG_NAME}>[\\s\\S]*?<\\/${MODIFICATIONS_TAG_NAME}>\\s+`,
|
||||||
@ -75,6 +75,15 @@ export function diffFiles(fileName: string, oldFileContent: string, newFileConte
|
|||||||
return unifiedDiff;
|
return unifiedDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const regex = new RegExp(`^${WORK_DIR}\/`);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strips out the work directory from the file path.
|
||||||
|
*/
|
||||||
|
export function extractRelativePath(filePath: string) {
|
||||||
|
return filePath.replace(regex, '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts the unified diff to HTML.
|
* Converts the unified diff to HTML.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user