{#if state.error.includes('not cloned locally') && hasUnlimitedAccess($userStore.userLevel)}
{/if}
{/if}
{#if state.clone.isCloned === false && !canUseApiFallback && tabs.length === 0}
{:else}
{#if state.ui.activeTab === 'files' && canViewRepo}
{
state.files.currentPath = path;
loadFiles(path);
}}
onNavigateBack={handleBack}
onContentChange={(content) => {
state.files.editedContent = content;
state.files.hasChanges = content !== state.files.content;
}}
isMaintainer={state.maintainers.isMaintainer}
readmeContent={state.preview.readme.content || null}
readmePath={state.preview.readme.path || null}
readmeHtml={state.preview.readme.html}
showFilePreview={state.preview.file.showPreview}
fileHtml={state.preview.file.html}
highlightedFileContent={state.preview.file.highlightedContent}
isImageFile={state.preview.file.isImage}
imageUrl={state.preview.file.imageUrl}
wordWrap={state.ui.wordWrap}
{supportsPreview}
onSave={() => {
if (!state.user.pubkey || !state.maintainers.isMaintainer || needsClone) return;
state.openDialog = 'commit';
}}
onTogglePreview={() => {
state.preview.file.showPreview = !state.preview.file.showPreview;
if (!state.preview.file.showPreview && state.files.content && state.files.currentFile) {
const ext = state.files.currentFile.split('.').pop() || '';
applySyntaxHighlighting(state.files.content, ext).catch(err => console.error('Error applying syntax highlighting:', err));
}
}}
onCopyFileContent={copyFileContent}
onDownloadFile={downloadFile}
copyingFile={state.preview.copying}
saving={state.saving}
needsClone={needsClone}
{cloneTooltip}
branches={state.git.branches}
currentBranch={state.git.currentBranch}
defaultBranch={state.git.defaultBranch}
onBranchChange={(branch) => {
state.git.currentBranch = branch;
handleBranchChangeDirect(branch);
}}
userPubkey={state.user.pubkey}
/>
{/if}
{#if state.ui.activeTab === 'history' && canViewRepo}
{
state.git.selectedCommit = hash;
viewDiff(hash);
}}
onVerify={async (hash) => {
state.git.verifyingCommits.add(hash);
try {
// Trigger verification logic - find the commit and verify
const commit = state.git.commits.find(c => (c.hash || (c as any).sha) === hash);
if (commit) {
await verifyCommit(hash);
}
} finally {
state.git.verifyingCommits.delete(hash);
}
}}
verifyingCommits={state.git.verifyingCommits}
showDiff={state.git.showDiff}
diffData={state.git.diffData}
/>
{/if}
state.git.selectedTag = tagName}
onTabChange={(tab) => state.ui.activeTab = tab as typeof state.ui.activeTab}
onToggleMobilePanel={() => state.ui.showLeftPanelOnMobile = !state.ui.showLeftPanelOnMobile}
onCreateTag={() => state.openDialog = 'createTag'}
onCreateRelease={(tagName, tagHash) => {
state.forms.release.tagName = tagName;
state.forms.release.tagHash = tagHash;
state.openDialog = 'createRelease';
}}
onLoadTags={loadTags}
/>
{#if state.ui.activeTab === 'code-search' && canViewRepo}
{/if}
{#if state.ui.activeTab === 'issues'}
{
state.selected.issue = id;
loadIssueReplies(id);
}}
onStatusUpdate={async (id, status) => {
// Find issue and update status
const issue = state.issues.find(i => i.id === id);
if (issue) {
await updateIssueStatus(id, issue.author, status as 'open' | 'closed' | 'resolved' | 'draft');
await loadIssues();
}
}}
issueReplies={state.issueReplies}
loadingReplies={state.loading.issueReplies}
/>
{/if}
{#if state.ui.activeTab === 'prs'}
{
state.selected.pr = id;
}}
onStatusUpdate={async (id, status) => {
// Find PR and update status - similar to updateIssueStatus
const pr = state.prs.find(p => p.id === id);
if (pr && state.user.pubkeyHex) {
// Check if user is maintainer or PR author
const isAuthor = state.user.pubkeyHex === pr.author;
if (!state.maintainers.isMaintainer && !isAuthor) {
alert('Only repository maintainers or PR authors can update PR status');
return;
}
try {
const response = await fetch(`/api/repos/${state.npub}/${state.repo}/prs`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
prId: id,
prAuthor: pr.author,
status
})
});
if (!response.ok) {
const data = await response.json();
throw new Error(data.state.error || 'Failed to update PR status');
}
await loadPRs();
} catch (err) {
state.error = err instanceof Error ? err.message : 'Failed to update PR status';
console.error('Error updating PR status:', err);
}
}
}}
/>
{/if}
{#if state.ui.activeTab === 'patches'}
{
state.selected.patch = id;
}}
onApply={async (id) => {
applying[id] = true;
try {
const patch = state.patches.find(p => p.id === id);
if (!patch) {
throw new Error('Patch not found');
}
if (!state.user.pubkey || !state.maintainers.isMaintainer || needsClone) {
alert('Only maintainers can apply patches');
return;
}
if (!confirm('Apply this patch to the repository? This will create a commit with the patch changes.')) {
return;
}
const authorEmail = await getUserEmail();
const authorName = await getUserName();
const response = await fetch(`/api/repos/${state.npub}/${state.repo}/patches/${id}/apply`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...buildApiHeaders()
},
body: JSON.stringify({
message: `Apply patch ${id.slice(0, 8)}: ${patch.subject}`,
authorName,
authorEmail,
branch: state.git.currentBranch || state.git.defaultBranch || 'main'
})
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.message || 'Failed to apply patch');
}
await loadPatches();
alert('Patch applied successfully!');
} catch (err) {
state.error = err instanceof Error ? err.message : 'Failed to apply patch';
console.error('Error applying patch:', err);
} finally {
applying[id] = false;
}
}}
{applying}
/>
{/if}
{#if state.ui.activeTab === 'discussions'}
{/if}
{#if state.ui.activeTab === 'docs'}
{/if}
{#if state.ui.activeTab === 'code-search' && canViewRepo}
{#if state.loading.codeSearch}
{:else if state.codeSearch.results.length > 0}
{/each}
{:else if state.codeSearch.query.trim() && !state.loading.codeSearch}
{/if}
{/if}
e.key === 'Enter' && performCodeSearch()}
class="code-search-input"
/>
Searching...
Found {state.codeSearch.results.length} result{state.codeSearch.results.length !== 1 ? 's' : ''}
{#each state.codeSearch.results as result}
{result.file}
Line {result.line}
{#if state.codeSearch.scope === 'all' && 'repo' in result}
{result.repo || state.npub}/{result.repo || state.repo}
{/if}
{result.content}
{#if state.error}
{:else}
{/if}
No results found
{/if}