Add deep-link support and fetch samples from GitHub URLs#16750
Conversation
Replace hardcoded sample workflow content with on-demand fetching from raw.githubusercontent.com/githubnext/agentics. Add hash-based deep linking so users can share direct links to specific samples or arbitrary GitHub workflow files: /editor/#issue-triage /editor/#https://github.com/user/repo/blob/main/workflow.md GitHub blob URLs are auto-converted to raw URLs. Fetched content is cached in-memory to avoid redundant requests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR modernizes the workflow editor by replacing ~290 lines of hardcoded workflow templates with on-demand fetching from the GitHub agentics repository. It introduces hash-based deep linking that allows users to share direct URLs to specific workflow samples or arbitrary GitHub workflow files. The implementation includes automatic URL conversion from GitHub blob URLs to raw URLs and in-memory caching to avoid redundant network requests.
Changes:
- Restructured the
SAMPLESobject to use URL references instead of inline content for most samples - Added URL conversion, fetching, and caching infrastructure with
toRawGitHubUrl()andfetchContent() - Implemented hash-based deep linking with support for sample keys and arbitrary GitHub URLs
- Updated initialization flow to load content from URL hash on startup
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -27,295 +31,77 @@ engine: copilot | |||
|
|
|||
| Say hello to the world! Check the current date and time, and greet the user warmly. | |||
| `, | |||
| }, | |||
| 'issue-triage': { | |||
| label: 'Issue Triage', | |||
| url: `${AGENTICS_RAW}/issue-triage.md`, | |||
| }, | |||
| 'ci-doctor': { | |||
| label: 'CI Doctor', | |||
| url: `${AGENTICS_RAW}/ci-doctor.md`, | |||
| }, | |||
| 'contribution-check': { | |||
| label: 'Contribution Guidelines Checker', | |||
| url: `${AGENTICS_RAW}/contribution-guidelines-checker.md`, | |||
| }, | |||
| 'daily-repo-status': { | |||
| label: 'Daily Repo Status', | |||
| url: `${AGENTICS_RAW}/daily-repo-status.md`, | |||
| }, | |||
| }; | |||
There was a problem hiding this comment.
The label properties in the SAMPLES object (lines 21, 36, 40, 44, 48) are defined but never used in the code. The dropdown options are hardcoded in the HTML file. Consider either removing these unused label properties or dynamically generating the dropdown options from the SAMPLES object to maintain a single source of truth.
| async function fetchContent(url) { | ||
| const rawUrl = toRawGitHubUrl(url); | ||
| if (contentCache.has(rawUrl)) return contentCache.get(rawUrl); | ||
| const resp = await fetch(rawUrl); | ||
| if (!resp.ok) throw new Error(`Failed to fetch ${rawUrl}: ${resp.status}`); | ||
| const text = await resp.text(); | ||
| contentCache.set(rawUrl, text); | ||
| return text; | ||
| } |
There was a problem hiding this comment.
The fetchContent function does not validate or sanitize arbitrary URLs before fetching them. Consider adding URL validation to ensure only allowed domains (e.g., raw.githubusercontent.com, github.com) are accessed, or implement appropriate CORS handling and error messaging for external URLs.
| await loadFromUrl(hash); | ||
| return true; | ||
| } | ||
|
|
There was a problem hiding this comment.
When an invalid hash is provided (not a recognized sample key and not a URL starting with http:// or https://), the function silently returns false without showing any error feedback to the user. According to the test plan, invalid URL hashes should show an error banner.
| // Invalid hash: show an error banner according to the test plan | |
| setStatus('error', 'Invalid URL hash'); | |
| errorText.textContent = 'Unrecognized sample key or URL in address bar.'; | |
| errorBanner.classList.remove('d-none'); |
| async function loadSample(key) { | ||
| const sample = SAMPLES[key]; | ||
| if (!sample) return; | ||
|
|
||
| // Sync dropdown | ||
| sampleSelect.value = key; | ||
| setHashQuietly(key); | ||
|
|
||
| if (sample.content) { | ||
| setEditorContent(sample.content); | ||
| return; | ||
| } | ||
|
|
||
| // Fetch from URL | ||
| setStatus('compiling', 'Fetching...'); | ||
| try { | ||
| const text = await fetchContent(sample.url); | ||
| sample.content = text; // cache on the sample object too | ||
| setEditorContent(text); | ||
| } catch (err) { | ||
| setStatus('error', 'Fetch failed'); | ||
| errorText.textContent = err.message; | ||
| errorBanner.classList.remove('d-none'); | ||
| } | ||
| } |
There was a problem hiding this comment.
There is no mechanism to cancel or track in-flight fetch requests. If a user rapidly switches between samples or changes the hash multiple times, multiple fetch requests will execute concurrently, and the last one to complete will set the editor content regardless of which sample the user actually selected most recently. Consider tracking and cancelling pending fetch requests (e.g., using AbortController) or implementing request queuing to ensure the displayed content matches the user's current selection.
Summary
raw.githubusercontent.com/githubnext/agenticsgithub.com/blob/URLs toraw.githubusercontent.comURLsDeep-link formats
/editor/#issue-triage/editor/#https://raw.githubusercontent.com/user/repo/main/workflow.md/editor/#https://github.com/user/repo/blob/main/workflow.mdTest plan
/editor/#issue-triage— fetches and loads Issue Triage from agentics repo/editor/#ci-doctor— fetches CI Doctor/editor/#https://github.com/githubnext/agentics/blob/main/workflows/daily-repo-status.md— auto-converts to raw URL and loads🤖 Generated with Claude Code