feat(integrations): add issue creation and Azure work item support
Add creation flow for integration issues and Azure work items. Expose Tauri commands to list Azure projects and types. Also add a command to create integration issues and return the created item. Preserve the target repository when provider responses omit it and return the created issue information to the UI. - Implement Azure-specific URL and payload handling and creation logic - Add a Svelte CreateIssueDialog and integrate it into IssueCenter - Add tests to validate creation requests and created-issue parsing
This commit is contained in:
@@ -6,8 +6,9 @@
|
||||
import { onMount, onDestroy, tick } from "svelte";
|
||||
import { fly } from "svelte/transition";
|
||||
import { cubicOut } from "svelte/easing";
|
||||
import { ChevronRight, CircleDot, FolderGit2, ExternalLink, RefreshCw, Search, Settings2, X, XCircle } from "@lucide/svelte";
|
||||
import { ChevronRight, CircleDot, Plus, FolderGit2, ExternalLink, RefreshCw, Search, Settings2, X, XCircle } from "@lucide/svelte";
|
||||
import "../issueWorkspace.css";
|
||||
import CreateIssueDialog from "./CreateIssueDialog.svelte";
|
||||
import IssueComments from "./IssueComments.svelte";
|
||||
import IssueLabels from "./IssueLabels.svelte";
|
||||
import IssueAssignees from "./IssueAssignees.svelte";
|
||||
@@ -17,13 +18,16 @@
|
||||
import { readWorkspacePreferences, writeWorkspacePreferences } from "../workspacePreferences";
|
||||
import { listIntegrationIssues, closeIntegrationIssue, listAzureIssueStates, setAzureIssueState, openInBrowser } from "../git";
|
||||
import { configuredIntegrationSources, integrationCredentialKey } from "../integrations";
|
||||
import type { GitIntegrationSettings, IntegrationIssue, StoredCredential } from "../types";
|
||||
import type { GitIntegrationSettings, GitIntegrationSource, IntegrationIssue, StoredCredential } from "../types";
|
||||
|
||||
export let language: "de" | "en" = "en";
|
||||
export let integrations: GitIntegrationSettings;
|
||||
export let loadCredential: (key: string) => Promise<StoredCredential | null>;
|
||||
export let onOpenSettings: () => void;
|
||||
|
||||
let createSource: GitIntegrationSource | null = null;
|
||||
let createKey = "";
|
||||
let createRepository = "";
|
||||
let viewMode: "list" | "board" = "list";
|
||||
let sourceId = "";
|
||||
let issues: IntegrationIssue[] = [];
|
||||
@@ -216,6 +220,25 @@
|
||||
} finally { closingId = ""; }
|
||||
}
|
||||
|
||||
function issueCreated(issue: IntegrationIssue) {
|
||||
const key = createKey;
|
||||
const saved = cache.get(key);
|
||||
const next = [issue, ...(saved?.issues ?? []).filter(item => item.id !== issue.id)];
|
||||
cache.set(key, { issues: next, nextCursor: saved?.nextCursor ?? null });
|
||||
createSource = null;
|
||||
if (sourceKey !== key) return;
|
||||
generation++; // Ignore any list response started before creation.
|
||||
loading = false;
|
||||
issues = next;
|
||||
viewMode = "list";
|
||||
repositoryFilter = ""; stateFilter = ""; query = "";
|
||||
const collapsed = new Set(collapsedRepositories);
|
||||
collapsed.delete(JSON.stringify([key, issue.repositoryName]));
|
||||
collapsedRepositories = collapsed;
|
||||
selectedId = issue.id;
|
||||
error = ""; actionError = "";
|
||||
}
|
||||
|
||||
async function openIssue(url: string) {
|
||||
try { await openInBrowser(url); }
|
||||
catch (cause) { error = String(cause); }
|
||||
@@ -249,6 +272,7 @@
|
||||
<SelectMenu class="repository-select" value={repositoryFilter} options={repositoryOptions} ariaLabel={de ? "Repository filtern" : "Filter repository"} onChange={value => { repositoryFilter = value; selectedId = ""; }} />
|
||||
<SelectMenu class="state-select" value={stateFilter} options={stateOptions} ariaLabel={de ? "Status filtern" : "Filter state"} onChange={value => { stateFilter = value; }} />
|
||||
<button class="workspace-button icon-button" disabled={loading} onclick={() => loadIssues()} title={de ? "Aktualisieren" : "Refresh"} aria-label={de ? "Aktualisieren" : "Refresh"}><RefreshCw size={15} /></button>
|
||||
{#if source}<button class="workspace-button issue-create-button" onclick={() => { createKey = sourceKey; createRepository = repositoryFilter; createSource = source; }}><Plus size={14}/>{de ? "Neues Issue" : "New issue"}</button>{/if}
|
||||
</div>
|
||||
{#if error}<div class="workspace-notice error" role="alert">{error}<p>{de ? "Bitte Token und Leserechte für Issues bzw. Azure Boards prüfen." : "Check the token and read permissions for issues or Azure Boards."}</p></div>{/if}
|
||||
<div class="issue-list">
|
||||
@@ -317,3 +341,7 @@
|
||||
{/if}
|
||||
{/if}
|
||||
</section>
|
||||
|
||||
{#if createSource}
|
||||
<CreateIssueDialog source={createSource} {de} initialRepository={createRepository} {loadCredential} onClose={() => { createSource = null; }} onCreated={issueCreated}/>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user