diff --git a/resources/js/components/AppHeader.vue b/resources/js/components/AppHeader.vue
index 0e1551f..70a5ec0 100644
--- a/resources/js/components/AppHeader.vue
+++ b/resources/js/components/AppHeader.vue
@@ -1,6 +1,13 @@
+
+
+
+
+
+ Branches
+
+ Matching branches are discovered from linked repositories
+ when the branch name starts with this ticket key.
+
+
+
+
+
+
+ Create branch
+
+
+
+
+ Create branch from ticket
+
+ Pick a linked repository, confirm the suggested
+ branch name, and create it directly in Gitea.
+
+
+
+
+
+
+
+
+
+
+ No matching branches were found across the linked repositories
+ you can access.
+
+
+
+
+
+
+ {{
+ repositoryBranch.repository_connection
+ .provider_label
+ }}
+
+
+ {{
+ repositoryBranch.repository_connection
+ .repository_full_name
+ }}
+
+
+
+
+ {{ repositoryBranch.repository_connection.base_url }}
+
+
+
+
+ Connect a matching Git account in your user settings
+ to inspect branches for this repository.
+
+
+
+
+ Open Git connections
+
+
+
+
+
+ {{ repositoryBranch.error }}
+
+
+
+
+ {{ branch.name }}
+
+
+
+
+
+
+
diff --git a/resources/js/components/TicketChildTicketsCard.vue b/resources/js/components/TicketChildTicketsCard.vue
new file mode 100644
index 0000000..32610d6
--- /dev/null
+++ b/resources/js/components/TicketChildTicketsCard.vue
@@ -0,0 +1,44 @@
+
+
+
+
+
+ Child tickets
+
+ Parent tickets expose their full child tree here, including
+ nested parent chains.
+
+
+
+
+
+ No child tickets are assigned to this ticket yet.
+
+
+
+
+
+
diff --git a/resources/js/components/TicketDetailsCard.vue b/resources/js/components/TicketDetailsCard.vue
new file mode 100644
index 0000000..c751d09
--- /dev/null
+++ b/resources/js/components/TicketDetailsCard.vue
@@ -0,0 +1,417 @@
+
+
+
+
+
+
+ Ticket details
+
+
+ {{
+ canEditTicket
+ ? 'Tracked ticket changes create worklog entries automatically.'
+ : 'You can review the tracked fields, but editing requires project edit permission.'
+ }}
+
+
+
+
+
+
+
+
diff --git a/resources/js/components/TicketLinkedTicketsCard.vue b/resources/js/components/TicketLinkedTicketsCard.vue
new file mode 100644
index 0000000..4961fc3
--- /dev/null
+++ b/resources/js/components/TicketLinkedTicketsCard.vue
@@ -0,0 +1,158 @@
+
+
+
+
+
+ Linked tickets
+
+ Track cross-ticket relationships with project-defined link
+ labels.
+
+
+
+
+
+
+ Link type
+
+
+ {{ ticketLinkType.label }}
+
+
+
+
+
+
+ Linked ticket
+
+
+ {{
+ `${ticketLinkOption.ticket_key} - ${ticketLinkOption.title}`
+ }}
+
+
+
+
+
+ Save link
+
+
+
+ No ticket links are configured for this ticket yet.
+
+
+
+
+
+
+ {{ linkedTicket.ticket_link_type.label }}
+
+
+ {{ linkedTicket.linked_ticket.ticket_key }}
+
+
+
+ {{ linkedTicket.linked_ticket.title }}
+
+
+
+
+ Remove
+
+
+
+
+
+
+
diff --git a/resources/js/components/TicketPullRequestsCard.vue b/resources/js/components/TicketPullRequestsCard.vue
new file mode 100644
index 0000000..150b4f2
--- /dev/null
+++ b/resources/js/components/TicketPullRequestsCard.vue
@@ -0,0 +1,134 @@
+
+
+
+
+
+ Pull requests
+
+ Matching pull requests are detected from linked repositories by
+ checking whether the source branch starts with this ticket key.
+
+
+
+
+
+ No matching pull requests were found across the linked
+ repositories you can access.
+
+
+
+
+
+
+ {{
+ repositoryPullRequest.repository_connection
+ .provider_label
+ }}
+
+
+ {{
+ repositoryPullRequest.repository_connection
+ .repository_full_name
+ }}
+
+
+
+
+ {{
+ repositoryPullRequest.repository_connection.base_url
+ }}
+
+
+
+
+ Connect a matching Git account in your user settings
+ to inspect pull requests for this repository.
+
+
+
+
+ Open Git connections
+
+
+
+
+
+ {{ repositoryPullRequest.error }}
+
+
+
+
+
+
+ Source branch: {{ pullRequest.source_branch }}
+
+
+
+
+
+
+
+
diff --git a/resources/js/components/TicketSnapshotCard.vue b/resources/js/components/TicketSnapshotCard.vue
new file mode 100644
index 0000000..caa266f
--- /dev/null
+++ b/resources/js/components/TicketSnapshotCard.vue
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+ Snapshot
+
+
+ Quick context for the ticket without scrolling through the
+ full detail form.
+
+
+
+
+
+
+ Assignee
+
+
+ {{ ticket.assignee?.name ?? 'Unassigned' }}
+
+
+
+
+
+ Author
+
+
+ {{ ticket.author?.name ?? 'No author' }}
+
+
+
+
+
+
+ Branches
+
+
+ {{ repositoryBranchCount }}
+
+
+
+
+
+ Pull requests
+
+
+ {{ pullRequestCount }}
+
+
+
+
+
+
+ Last updated
+
+
+ {{ formatDateTime(ticket.updated_at) }}
+
+
+
+
+
+
+
+
diff --git a/resources/js/components/TicketWorklogCard.vue b/resources/js/components/TicketWorklogCard.vue
new file mode 100644
index 0000000..c9e77c9
--- /dev/null
+++ b/resources/js/components/TicketWorklogCard.vue
@@ -0,0 +1,67 @@
+
+
+
+
+
+ Worklog
+
+ Every tracked ticket change is recorded with actor and
+ timestamp.
+
+
+
+
+
+ No worklog entries exist for this ticket yet.
+
+
+
+
+
+
+ {{ worklogEntry.entry_type }}
+
+
+ {{ worklogEntry.actor?.name ?? 'System' }}
+
+
+
+ {{ worklogEntry.summary }}
+
+
+ {{ formatDateTime(worklogEntry.created_at) }}
+
+
+
+
+
+
diff --git a/resources/js/components/UserMenuContent.vue b/resources/js/components/UserMenuContent.vue
index f1491e0..0dbfe38 100644
--- a/resources/js/components/UserMenuContent.vue
+++ b/resources/js/components/UserMenuContent.vue
@@ -43,7 +43,7 @@ const { appearance, updateAppearance } = useAppearance();
-
+
Appearance
-import { Form, useForm, Head, Link, usePage } from '@inertiajs/vue3';
-import { CheckCircle2, GitBranchPlus, XCircle } from 'lucide-vue-next';
-import { computed, ref, watch } from 'vue';
-import ProjectTicketBranchController from '@/actions/App/Http/Controllers/ProjectTicketBranchController';
-import ProjectTicketLinkController from '@/actions/App/Http/Controllers/ProjectTicketLinkController';
-import ProjectTicketController from '@/actions/App/Http/Controllers/ProjectTicketController';
-import FeatureComingSoonPanel from '@/components/FeatureComingSoonPanel.vue';
-import InputError from '@/components/InputError.vue';
+import { Head, Link } from '@inertiajs/vue3';
+import { computed } from 'vue';
+import TicketBranchesCard from '@/components/TicketBranchesCard.vue';
+import TicketChildTicketsCard from '@/components/TicketChildTicketsCard.vue';
+import TicketDetailsCard from '@/components/TicketDetailsCard.vue';
+import TicketLinkedTicketsCard from '@/components/TicketLinkedTicketsCard.vue';
+import TicketPullRequestsCard from '@/components/TicketPullRequestsCard.vue';
+import TicketSnapshotCard from '@/components/TicketSnapshotCard.vue';
+import TicketWorklogCard from '@/components/TicketWorklogCard.vue';
import TicketPriorityIcon from '@/components/TicketPriorityIcon.vue';
-import TicketTreeList from '@/components/TicketTreeList.vue';
import TicketTypeIcon from '@/components/TicketTypeIcon.vue';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
-import {
- Card,
- CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
-} from '@/components/ui/card';
-import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogFooter,
- DialogHeader,
- DialogTitle,
-} from '@/components/ui/dialog';
-import { Checkbox } from '@/components/ui/checkbox';
-import { Input } from '@/components/ui/input';
-import { Label } from '@/components/ui/label';
-import {
- Select,
- SelectContent,
- SelectItem,
- SelectTrigger,
- SelectValue,
-} from '@/components/ui/select';
-import { Textarea } from '@/components/ui/textarea';
import AppLayout from '@/layouts/AppLayout.vue';
-import { edit as editGitConnections } from '@/routes/git-connections/index';
+import { airyOutlineButtonClass } from '@/lib/ticket-styles';
import { index as backlogIndex } from '@/routes/projects/backlog';
import { index as boardIndex } from '@/routes/projects/board';
import { index as projectIndex, show } from '@/routes/projects/index';
import { show as showTicket } from '@/routes/projects/tickets';
-import type { BranchNameValidationModel } from '@/types/models/branch-name-validation-model';
-import type { RepositoryConnectionModel } from '@/types/models/repository-connection-model';
import type { BreadcrumbItem, ProjectTicketPageProps } from '@/types';
const props = defineProps();
-const page = usePage();
-const appName = String(page.props.name);
-const visibleRepositoryBranches = computed(() =>
- props.repositoryBranches.filter(
- (repositoryBranch) =>
- repositoryBranch.branches.length > 0 ||
- repositoryBranch.error !== null ||
- !repositoryBranch.repository_connection.has_personal_access,
- ),
-);
-
-const visibleRepositoryPullRequests = computed(() =>
- props.repositoryPullRequests.filter(
- (repositoryPullRequest) =>
- repositoryPullRequest.pull_requests.length > 0 ||
- repositoryPullRequest.error !== null ||
- !repositoryPullRequest.repository_connection.has_personal_access,
- ),
-);
-
-const linkedRepositoryConnections = computed(() =>
- props.repositoryBranches.map(
- (repositoryBranch) => repositoryBranch.repository_connection,
- ),
-);
-
-const canCreateBranches = computed(
- () => props.canEditTicket && linkedRepositoryConnections.value.length > 0,
-);
const canEditAuthor = computed(
() => props.canEditTicket && props.canManageProject,
);
@@ -86,16 +29,6 @@ const canViewAuthor = computed(
() => props.project.show_author || props.canManageProject,
);
-const defaultBranchRepositoryConnectionId = computed(() =>
- String(
- linkedRepositoryConnections.value.find(
- (repositoryConnection) => repositoryConnection.has_personal_access,
- )?.id ??
- linkedRepositoryConnections.value[0]?.id ??
- '',
- ),
-);
-
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Projects',
@@ -113,301 +46,6 @@ const breadcrumbs: BreadcrumbItem[] = [
}),
},
];
-
-const frostedCardClass =
- 'rounded-[1.75rem] border-white/70 bg-white/85 shadow-[0_22px_65px_-40px_rgba(45,51,53,0.38)] backdrop-blur-sm dark:border-white/10 dark:bg-card/90 dark:shadow-black/25';
-const frostedAsideCardClass =
- 'h-fit rounded-[1.75rem] border-white/70 bg-white/85 shadow-[0_22px_65px_-40px_rgba(45,51,53,0.38)] backdrop-blur-sm dark:border-white/10 dark:bg-card/90 dark:shadow-black/25';
-const airyOutlineButtonClass =
- 'rounded-full border-white/70 bg-white/80 text-[#2d3335] shadow-[0_18px_45px_-34px_rgba(45,51,53,0.34)] hover:bg-white dark:border-white/10 dark:bg-card/85 dark:text-foreground dark:hover:bg-card';
-const inputClass =
- 'h-12 rounded-xl border-white/70 bg-white/80 text-[#2d3335] shadow-[0_18px_45px_-34px_rgba(45,51,53,0.22)] focus-visible:border-[#9de77c] focus-visible:ring-[#abf688]/35 dark:border-white/10 dark:bg-card/90 dark:text-foreground dark:focus-visible:border-primary';
-const textareaClass =
- 'min-h-32 rounded-[1.25rem] border-white/70 bg-white/80 text-[#2d3335] shadow-[0_18px_45px_-34px_rgba(45,51,53,0.22)] focus-visible:border-[#9de77c] focus-visible:ring-[#abf688]/35 dark:border-white/10 dark:bg-card/90 dark:text-foreground dark:focus-visible:border-primary';
-const nativeSelectClass =
- 'h-12 w-full rounded-xl border border-white/70 bg-white/80 px-3 py-2 text-sm text-[#2d3335] shadow-[0_18px_45px_-34px_rgba(45,51,53,0.22)] outline-none transition-[color,box-shadow] focus:border-[#9de77c] focus:ring-4 focus:ring-[#abf688]/35 disabled:cursor-not-allowed disabled:opacity-60 dark:border-white/10 dark:bg-card/90 dark:text-foreground dark:focus:border-primary dark:focus:ring-primary/20';
-const selectTriggerClass =
- 'h-12 w-full rounded-xl border-white/70 bg-white/80 text-left text-[#2d3335] shadow-[0_18px_45px_-34px_rgba(45,51,53,0.22)] focus:border-[#9de77c] focus:ring-[#abf688]/35 dark:border-white/10 dark:bg-card/90 dark:text-foreground dark:focus:border-primary';
-const selectContentClass =
- 'rounded-[1.25rem] border-white/80 bg-white/95 shadow-[0_24px_60px_-40px_rgba(45,51,53,0.34)] backdrop-blur-sm dark:border-white/10 dark:bg-card/95';
-const fieldLabelClass =
- 'text-[0.72rem] font-semibold uppercase tracking-[0.18em] text-[#5a6062]';
-
-const form = useForm({
- acceptance_criteria: props.ticket.acceptance_criteria ?? '',
- assignee_user_id: props.ticket.assignee_user_id ?? '',
- author_user_id: props.ticket.author_user_id ?? '',
- blocked_comment: props.ticket.blocked_comment ?? '',
- description: props.ticket.description ?? '',
- field_values: props.ticketFieldDefinitions.map((ticketFieldDefinition) => {
- const currentFieldValue = props.ticket.field_values?.find(
- (fieldValue) =>
- fieldValue.ticket_field_definition_id ===
- ticketFieldDefinition.id,
- );
-
- return {
- ticket_field_definition_id: ticketFieldDefinition.id,
- value_number: currentFieldValue?.value_number ?? '',
- value_user_id: currentFieldValue?.value_user_id ?? '',
- };
- }),
- is_blocked: props.ticket.is_blocked,
- parent_ticket_id: props.ticket.parent_ticket_id ?? '',
- ticket_priority_id: String(props.ticket.ticket_priority_id),
- ticket_type_id: String(props.ticket.ticket_type_id),
- title: props.ticket.title,
- story_points: props.ticket.story_points,
-});
-
-const selectedTicketType = computed(
- () =>
- props.ticketTypes.find(
- (ticketType) => String(ticketType.id) === form.ticket_type_id,
- ) ?? props.ticket.ticket_type,
-);
-
-const selectedTicketPriority = computed(
- () =>
- props.ticketPriorities.find(
- (ticketPriority) =>
- String(ticketPriority.id) === form.ticket_priority_id,
- ) ?? props.ticket.ticket_priority,
-);
-
-const selectedAssignee = computed(
- () =>
- props.users.find(
- (user) => String(user.id) === String(form.assignee_user_id),
- ) ?? null,
-);
-
-const selectedAuthor = computed(
- () =>
- props.users.find(
- (user) => String(user.id) === String(form.author_user_id),
- ) ?? null,
-);
-
-const repositoryBranchCount = computed(() =>
- visibleRepositoryBranches.value.reduce(
- (count, repositoryBranch) => count + repositoryBranch.branches.length,
- 0,
- ),
-);
-
-const pullRequestCount = computed(() =>
- visibleRepositoryPullRequests.value.reduce(
- (count, repositoryPullRequest) =>
- count + repositoryPullRequest.pull_requests.length,
- 0,
- ),
-);
-
-const isCreateBranchDialogOpen = ref(false);
-const isCheckingBranchName = ref(false);
-const branchNameValidation = ref(null);
-
-const branchCreationForm = useForm<{
- branch_name: string;
- repository_connection_id: string;
-}>({
- branch_name: props.suggestedBranchName,
- repository_connection_id: defaultBranchRepositoryConnectionId.value,
-});
-
-const selectedBranchRepositoryConnection = computed(
- (): RepositoryConnectionModel | null =>
- linkedRepositoryConnections.value.find(
- (repositoryConnection) =>
- String(repositoryConnection.id) ===
- branchCreationForm.repository_connection_id,
- ) ?? null,
-);
-
-const selectedBranchRepositoryHasPersonalAccess = computed(
- () =>
- selectedBranchRepositoryConnection.value?.has_personal_access ?? false,
-);
-
-const initializeBranchCreationForm = (): void => {
- branchCreationForm.clearErrors();
- branchCreationForm.branch_name = props.suggestedBranchName;
- branchCreationForm.repository_connection_id =
- defaultBranchRepositoryConnectionId.value;
- branchNameValidation.value = null;
- isCheckingBranchName.value = false;
-};
-
-watch(
- () => isCreateBranchDialogOpen.value,
- (isOpen) => {
- if (!isOpen) {
- branchCreationForm.clearErrors();
- branchNameValidation.value = null;
- isCheckingBranchName.value = false;
-
- return;
- }
-
- initializeBranchCreationForm();
- },
-);
-
-watch(
- [
- () => isCreateBranchDialogOpen.value,
- () => branchCreationForm.repository_connection_id,
- () => branchCreationForm.branch_name,
- ],
- (
- [isOpen, repositoryConnectionId, branchName],
- _previousValues,
- onCleanup,
- ) => {
- if (!isOpen) {
- return;
- }
-
- const repositoryConnection = selectedBranchRepositoryConnection.value;
-
- if (repositoryConnection === null || repositoryConnectionId === '') {
- branchNameValidation.value = null;
- isCheckingBranchName.value = false;
-
- return;
- }
-
- if (!repositoryConnection.has_personal_access) {
- branchNameValidation.value = {
- is_valid: false,
- message:
- 'Connect a matching Git connection in your user settings first.',
- };
- isCheckingBranchName.value = false;
-
- return;
- }
-
- if (branchName.trim() === '') {
- branchNameValidation.value = {
- is_valid: false,
- message: 'Branch name is required.',
- };
- isCheckingBranchName.value = false;
-
- return;
- }
-
- const abortController = new AbortController();
- const timeoutId = window.setTimeout(async () => {
- isCheckingBranchName.value = true;
-
- try {
- const response = await fetch(
- ProjectTicketBranchController.validate.url(
- {
- project: props.project.id,
- ticket: props.ticket.id,
- },
- {
- query: {
- branch_name: branchName,
- repository_connection_id:
- repositoryConnectionId,
- },
- },
- ),
- {
- credentials: 'same-origin',
- headers: {
- Accept: 'application/json',
- 'X-Requested-With': 'XMLHttpRequest',
- },
- method: 'GET',
- signal: abortController.signal,
- },
- );
-
- if (!response.ok) {
- throw new Error('Branch validation failed.');
- }
-
- branchNameValidation.value =
- (await response.json()) as BranchNameValidationModel;
- } catch (error) {
- if (
- error instanceof DOMException &&
- error.name === 'AbortError'
- ) {
- return;
- }
-
- branchNameValidation.value = {
- is_valid: false,
- message: `${appName} could not validate this branch name right now.`,
- };
- } finally {
- if (!abortController.signal.aborted) {
- isCheckingBranchName.value = false;
- }
- }
- }, 300);
-
- onCleanup(() => {
- abortController.abort();
- window.clearTimeout(timeoutId);
- isCheckingBranchName.value = false;
- });
- },
- { immediate: true },
-);
-
-const submitBranchCreation = (): void => {
- if (
- !canCreateBranches.value ||
- !selectedBranchRepositoryHasPersonalAccess.value ||
- branchNameValidation.value?.is_valid !== true
- ) {
- return;
- }
-
- branchCreationForm.submit(
- ProjectTicketBranchController.store({
- project: props.project.id,
- ticket: props.ticket.id,
- }),
- {
- onSuccess: () => {
- isCreateBranchDialogOpen.value = false;
- },
- preserveScroll: true,
- },
- );
-};
-
-const submit = (): void => {
- if (!props.canEditTicket) {
- return;
- }
-
- form.submit(
- ProjectTicketController.update({
- project: props.project.id,
- ticket: props.ticket.id,
- }),
- {
- preserveScroll: true,
- },
- );
-};
-
-const formatDateTime = (value: string): string => {
- return new Intl.DateTimeFormat(undefined, {
- dateStyle: 'medium',
- timeStyle: 'short',
- }).format(new Date(value));
-};
@@ -439,7 +77,7 @@ const formatDateTime = (value: string): string => {
class="dark:bg-card/80 dark:text-foreground gap-2 rounded-full border-white/70 bg-white/70 px-3 py-1.5 text-[#2d3335] shadow-[0_16px_40px_-34px_rgba(45,51,53,0.3)] dark:border-white/10"
>
- {{ selectedTicketType.name }}
+ {{ ticket.ticket_type.name }}
{
class="dark:bg-card/80 dark:text-foreground gap-2 rounded-full border-white/70 bg-white/70 px-3 py-1.5 text-[#2d3335] shadow-[0_16px_40px_-34px_rgba(45,51,53,0.3)] dark:border-white/10"
>
- {{ selectedTicketPriority.name }}
+ {{ ticket.ticket_priority.name }}
{
variant="outline"
:class="airyOutlineButtonClass"
>
- Open board
+
+ Open board
+
{
variant="outline"
:class="airyOutlineButtonClass"
>
- Back to project
+
+ Back to project
+
@@ -539,1197 +177,56 @@ const formatDateTime = (value: string): string => {
-
-
-
- Ticket details
-
-
- {{
- canEditTicket
- ? 'Tracked ticket changes create worklog entries automatically.'
- : 'You can review the tracked fields, but editing requires project edit permission.'
- }}
-
-
-
-
-
-
-
- Title
-
-
-
-
-
-
-
-
- Type
-
-
-
-
-
-
-
-
-
- {{ ticketType.name }}
-
-
-
-
-
-
-
-
-
- Priority
-
-
-
-
-
-
-
-
-
- {{ ticketPriority.name }}
-
-
-
-
-
-
-
-
-
-
-
- Assignee
-
-
- Unassigned
-
- {{ user.name }}
-
-
-
-
-
-
-
- Author
-
-
- No author
-
- {{ user.name }}
-
-
-
-
-
-
-
-
- Estimated story points
-
-
-
-
-
-
-
- Parent ticket
-
-
- No parent ticket
-
- {{
- `${parentTicketOption.ticket_key} - ${parentTicketOption.title}`
- }}
-
-
-
-
-
-
-
- Description
-
-
-
-
-
-
-
- Acceptance criteria
-
-
-
-
-
-
-
-
- (form.is_blocked =
- value === true)
- "
- />
-
- Mark ticket as blocked
-
-
-
-
-
- Blocker comment
-
-
-
-
-
-
-
-
-
- Custom fields
-
-
- Project-configured fields can be tracked
- directly on the ticket.
-
-
-
-
- No custom fields are configured for this
- project yet.
-
-
-
-
-
- {{ ticketFieldDefinition.label }}
-
-
-
- Unassigned
-
- {{ user.name }}
-
-
-
-
-
-
-
-
-
-
-
-
- Save changes
-
-
-
-
-
+
-
-
-
- Branches
-
- Matching branches are discovered from linked
- repositories when the branch name starts
- with this ticket key.
-
-
+
-
-
-
- Create branch
-
+
-
-
-
- Create branch from ticket
-
-
- Pick a linked repository, confirm
- the suggested branch name, and
- create it directly in Gitea.
-
-
+
-
-
-
- Repository
-
-
-
- {{
- `${repositoryConnection.repository_full_name}${repositoryConnection.has_personal_access ? '' : ' (connect personal Git access)'}`
- }}
-
-
-
-
+
-
-
- Branch name
-
-
-
-
-
-
-
-
-
-
- {{
- isCheckingBranchName
- ? 'Checking whether this branch name is valid and still available...'
- : (branchNameValidation?.message ??
- 'Select a linked repository to validate the branch name.')
- }}
-
-
-
-
-
-
- You can only create branches in
- repositories that match one of
- your personal Git connections.
-
-
-
-
- Open Git connections
-
-
-
-
-
-
- Cancel
-
-
-
- Create now
-
-
-
-
-
-
-
-
-
- No matching branches were found across the
- linked repositories you can access.
-
-
-
-
-
-
- {{
- repositoryBranch
- .repository_connection
- .provider_label
- }}
-
-
- {{
- repositoryBranch
- .repository_connection
- .repository_full_name
- }}
-
-
-
-
- {{
- repositoryBranch
- .repository_connection.base_url
- }}
-
-
-
-
- Connect a matching Git account in
- your user settings to inspect
- branches for this repository.
-
-
-
-
- Open Git connections
-
-
-
-
-
- {{ repositoryBranch.error }}
-
-
-
-
- {{ branch.name }}
-
-
-
-
-
-
-
-
-
- Linked tickets
-
- Track cross-ticket relationships with
- project-defined link labels.
-
-
-
-
-
-
-
- Link type
-
-
-
- {{ ticketLinkType.label }}
-
-
-
-
-
-
-
- Linked ticket
-
-
-
- {{
- `${ticketLinkOption.ticket_key} - ${ticketLinkOption.title}`
- }}
-
-
-
-
-
-
- Save link
-
-
-
-
- No ticket links are configured for this ticket
- yet.
-
-
-
-
-
-
- {{
- linkedTicket.ticket_link_type
- .label
- }}
-
-
- {{
- linkedTicket.linked_ticket
- .ticket_key
- }}
-
-
-
- {{ linkedTicket.linked_ticket.title }}
-
-
-
-
- Remove
-
-
-
-
-
-
-
-
-
- Pull requests
-
- Matching pull requests are detected from linked
- repositories by checking whether the source
- branch starts with this ticket key.
-
-
-
-
-
- No matching pull requests were found across the
- linked repositories you can access.
-
-
-
-
-
-
- {{
- repositoryPullRequest
- .repository_connection
- .provider_label
- }}
-
-
- {{
- repositoryPullRequest
- .repository_connection
- .repository_full_name
- }}
-
-
-
-
- {{
- repositoryPullRequest
- .repository_connection.base_url
- }}
-
-
-
-
- Connect a matching Git account in
- your user settings to inspect pull
- requests for this repository.
-
-
-
-
- Open Git connections
-
-
-
-
-
- {{ repositoryPullRequest.error }}
-
-
-
-
-
-
- Source branch:
- {{ pullRequest.source_branch }}
-
-
-
-
-
-
-
-
-
-
- Child tickets
-
- Parent tickets expose their full child tree
- here, including nested parent chains.
-
-
-
-
-
- No child tickets are assigned to this ticket
- yet.
-
-
-
-
-
-
-
-
- Worklog
-
- Every tracked ticket change is recorded with
- actor and timestamp.
-
-
-
-
-
- No worklog entries exist for this ticket yet.
-
-
-
-
-
-
- {{ worklogEntry.entry_type }}
-
-
- {{
- worklogEntry.actor?.name ??
- 'System'
- }}
-
-
-
- {{ worklogEntry.summary }}
-
-
- {{
- formatDateTime(
- worklogEntry.created_at,
- )
- }}
-
-
-
-
-
+
-
-
-
-
- Snapshot
-
-
- Quick context for the ticket without scrolling
- through the full detail form.
-
-
-
-
-
-
- Assignee
-
-
- {{ selectedAssignee?.name ?? 'Unassigned' }}
-
-
-
-
-
- Author
-
-
- {{ selectedAuthor?.name ?? 'No author' }}
-
-
-
-
-
-
- Branches
-
-
- {{ repositoryBranchCount }}
-
-
-
-
-
- Pull requests
-
-
- {{ pullRequestCount }}
-
-
-
-
-
-
- Last updated
-
-
- {{ formatDateTime(ticket.updated_at) }}
-
-
-
-
-
-
+
diff --git a/resources/js/pages/projects/settings/Repositories.vue b/resources/js/pages/projects/settings/Repositories.vue
index 8ee4a54..0218128 100644
--- a/resources/js/pages/projects/settings/Repositories.vue
+++ b/resources/js/pages/projects/settings/Repositories.vue
@@ -287,9 +287,9 @@ const submitUpdate = (): void => {
- Without a matching personal connection, {{ appName }} only
- shows the repository name and links you to your user
- settings.
+ Without a matching personal connection,
+ {{ appName }} only shows the repository name and links
+ you to your user settings.
@@ -614,8 +614,8 @@ const submitUpdate = (): void => {
>
This project link is visible, but you need a
matching Git connection in your user
- settings before {{ appName }} can open or query
- this repository for you.
+ settings before {{ appName }} can open or
+ query this repository for you.
@@ -650,9 +650,9 @@ const submitUpdate = (): void => {
Detected personal sources
- {{ appName }} loads repositories from your personal
- Git connections and offers them for project
- linking.
+ {{ appName }} loads repositories from your
+ personal Git connections and offers them for
+ project linking.
diff --git a/resources/js/pages/settings/GitConnections.vue b/resources/js/pages/settings/GitConnections.vue
index 28b9f09..811ed20 100644
--- a/resources/js/pages/settings/GitConnections.vue
+++ b/resources/js/pages/settings/GitConnections.vue
@@ -46,8 +46,9 @@ const breadcrumbItems: BreadcrumbItem[] = [
/>
Each user needs their own application key. Without a
- matching personal connection, {{ appName }} can only show
- repository names and will link you back to this page.
+ matching personal connection, {{ appName }} can only
+ show repository names and will link you back to this
+ page.