mirror of
https://github.com/go-gitea/gitea.git
synced 2026-04-04 07:55:31 +02:00
reload page partially
This commit is contained in:
parent
36810b8900
commit
7762325ebf
@ -9,7 +9,7 @@
|
||||
<span class="ui inline required field">
|
||||
<label>{{ctx.Locale.Tr "actions.workflow.from_ref"}}:</label>
|
||||
</span>
|
||||
<div class="ui inline field dropdown button select-branch branch-selector-dropdown ellipsis-text-items">
|
||||
<div class="ui inline field dropdown button select-branch branch-selector-dropdown ellipsis-text-items" data-global-init="initSelectBranchDropdown">
|
||||
<input type="hidden" name="ref" hx-sync="this:replace" hx-target="#runWorkflowDispatchModalInputs" hx-swap="innerHTML" hx-get="{{$.Link}}/workflow-dispatch-inputs?workflow={{$.CurWorkflow}}" hx-trigger="change" value="refs/heads/{{index .Branches 0}}">
|
||||
{{svg "octicon-git-branch" 14}}
|
||||
<div class="default text">{{index .Branches 0}}</div>
|
||||
|
||||
@ -16,6 +16,7 @@ Still needs to figure out:
|
||||
{{if and (not .Issue.IsPull) (not .PageIsComparePull)}}
|
||||
<input id="ref_selector" name="ref" type="hidden" value="{{.Reference}}">
|
||||
<div class="ui dropdown select-branch branch-selector-dropdown ellipsis-text-items {{if not .HasIssuesOrPullsWritePermission}}disabled{{end}}"
|
||||
data-global-init="initSelectBranchDropdown"
|
||||
data-no-results="{{ctx.Locale.Tr "no_results_found"}}"
|
||||
{{if and .Issue (or .IsIssueWriter .HasIssuesOrPullsWritePermission)}}data-url-update-issueref="{{$.RepoLink}}/issues/{{.Issue.Index}}/ref"{{end}}
|
||||
>
|
||||
|
||||
@ -46,7 +46,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="issue-content-right ui segment">
|
||||
<div class="issue-content-right ui segment" data-global-init="initRepoIssueSidebar">
|
||||
{{template "repo/issue/branch_selector_field" $}}{{/* TODO: RemoveIssueRef: template "repo/issue/branch_selector_field" $*/}}
|
||||
|
||||
{{if .PageIsComparePull}}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<div class="issue-content-right ui segment">
|
||||
<div class="issue-content-right ui segment" data-global-init="initRepoIssueSidebar">
|
||||
{{template "repo/issue/branch_selector_field" $}}{{/* TODO: RemoveIssueRef: template "repo/issue/branch_selector_field" $*/}}
|
||||
|
||||
{{if .Issue.IsPull}}
|
||||
|
||||
@ -1,27 +1,8 @@
|
||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {GET, POST} from '../modules/fetch.ts';
|
||||
import {showErrorToast} from '../modules/toast.ts';
|
||||
import {addDelegatedEventListener, queryElemChildren, queryElems, toggleElem} from '../utils/dom.ts';
|
||||
|
||||
// if there are draft comments, confirm before reloading, to avoid losing comments
|
||||
function issueSidebarReloadConfirmDraftComment() {
|
||||
const commentTextareas = [
|
||||
document.querySelector<HTMLTextAreaElement>('.edit-content-zone:not(.tw-hidden) textarea'),
|
||||
document.querySelector<HTMLTextAreaElement>('#comment-form textarea'),
|
||||
];
|
||||
for (const textarea of commentTextareas) {
|
||||
// Most users won't feel too sad if they lose a comment with 10 chars, they can re-type these in seconds.
|
||||
// But if they have typed more (like 50) chars and the comment is lost, they will be very unhappy.
|
||||
if (textarea && textarea.value.trim().length > 10) {
|
||||
textarea.parentElement!.scrollIntoView();
|
||||
if (!window.confirm('Page will be reloaded, but there are draft comments. Continuing to reload will discard the comments. Continue?')) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
window.location.reload();
|
||||
}
|
||||
import {parseDom} from "../utils.ts";
|
||||
|
||||
export class IssueSidebarComboList {
|
||||
updateUrl: string;
|
||||
@ -33,6 +14,9 @@ export class IssueSidebarComboList {
|
||||
initialValues: string[];
|
||||
container: HTMLElement;
|
||||
|
||||
elIssueMainContent: HTMLElement;
|
||||
elIssueSidebar: HTMLElement;
|
||||
|
||||
constructor(container: HTMLElement) {
|
||||
this.container = container;
|
||||
this.updateUrl = container.getAttribute('data-update-url')!;
|
||||
@ -43,6 +27,9 @@ export class IssueSidebarComboList {
|
||||
this.elDropdown = container.querySelector<HTMLElement>(':scope > .ui.dropdown')!;
|
||||
this.elList = container.querySelector<HTMLElement>(':scope > .ui.list')!;
|
||||
this.elComboValue = container.querySelector<HTMLInputElement>(':scope > .combo-value')!;
|
||||
|
||||
this.elIssueMainContent = document.querySelector('.issue-content-left')!;
|
||||
this.elIssueSidebar = document.querySelector('.issue-content-right')!;
|
||||
}
|
||||
|
||||
collectCheckedValues() {
|
||||
@ -63,6 +50,34 @@ export class IssueSidebarComboList {
|
||||
toggleElem(elEmptyTip, !hasItems);
|
||||
}
|
||||
|
||||
async reloadPagePartially() {
|
||||
const resp = await GET(window.location.href);
|
||||
if (!resp.ok) throw new Error(`Failed to reload page: ${resp.statusText}`);
|
||||
const doc = parseDom(await resp.text(), 'text/html');
|
||||
|
||||
// we can safely replace the whole right part (sidebar) because there are only some dropdowns and lists
|
||||
const newSidebar = doc.querySelector('.issue-content-right')!;
|
||||
this.elIssueSidebar.replaceWith(newSidebar);
|
||||
|
||||
// for the main content (left side), at the moment we only support adding new timeline items
|
||||
const newMainContent = doc.querySelector('.issue-content-left')!;
|
||||
|
||||
// find the last ".timeline-item[id]" in current main content, and insert new items after it, some cases:
|
||||
// * a new empty issue: "timeline-item comment first", "timeline-item comment form (optional)"
|
||||
// * issue with timeline events: "timeline-item comment first", "timeline-item event"+id, "timeline-item comment form (optional)"
|
||||
const timelineItemsWithId = this.elIssueMainContent.querySelectorAll('.timeline-item[id]');
|
||||
let lastTimelineItemForInsertion = timelineItemsWithId[timelineItemsWithId.length - 1] ?? this.elIssueMainContent.querySelector('.timeline-item');
|
||||
if (!lastTimelineItemForInsertion) return;
|
||||
|
||||
const newTimelineItems = newMainContent.querySelectorAll(`.timeline-item[id]`);
|
||||
for (const newItem of newTimelineItems) {
|
||||
const newItemId = newItem.getAttribute('id')!;
|
||||
if (this.elIssueMainContent.querySelector(`.timeline-item[id="${CSS.escape(newItemId)}"]`)) continue;
|
||||
lastTimelineItemForInsertion.insertAdjacentElement('afterend', newItem);
|
||||
lastTimelineItemForInsertion = newItem;
|
||||
}
|
||||
}
|
||||
|
||||
async sendRequestToBackend(changedValues: Array<string>): Promise<Response> {
|
||||
if (!changedValues.length) throw new Error('No changed values to update');
|
||||
let lastResp: Response | null = null;
|
||||
@ -85,15 +100,18 @@ export class IssueSidebarComboList {
|
||||
|
||||
async updateToBackend(changedValues: Array<string>) {
|
||||
if (!changedValues.length) return;
|
||||
this.elIssueSidebar.classList.add('is-loading');
|
||||
try {
|
||||
const resp = await this.sendRequestToBackend(changedValues);
|
||||
if (!resp.ok) {
|
||||
showErrorToast(`Failed to update to backend: ${resp.statusText}`);
|
||||
return;
|
||||
}
|
||||
issueSidebarReloadConfirmDraftComment();
|
||||
await this.reloadPagePartially();
|
||||
} catch (e) {
|
||||
showErrorToast(`Failed to update to backend: ${e}`);
|
||||
} finally {
|
||||
this.elIssueSidebar.classList.remove('is-loading');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,18 +1,20 @@
|
||||
import {POST} from '../modules/fetch.ts';
|
||||
import {queryElems, toggleElem} from '../utils/dom.ts';
|
||||
import {IssueSidebarComboList} from './repo-issue-sidebar-combolist.ts';
|
||||
import {registerGlobalInitFunc} from '../modules/observer.ts';
|
||||
|
||||
function initBranchSelector() {
|
||||
// TODO: RemoveIssueRef: see "repo/issue/branch_selector_field.tmpl"
|
||||
const elSelectBranch = document.querySelector('.ui.dropdown.select-branch.branch-selector-dropdown');
|
||||
if (!elSelectBranch) return;
|
||||
|
||||
function initBranchSelector(elSelectBranch: HTMLElement) {
|
||||
// At the moment, 2 places:
|
||||
// * Issue sidebar branch selector, TODO: RemoveIssueRef: see "repo/issue/branch_selector_field.tmpl"
|
||||
// * Workflow dispatch branch selector
|
||||
const urlUpdateIssueRef = elSelectBranch.getAttribute('data-url-update-issueref');
|
||||
const elBranchMenu = elSelectBranch.querySelector('.reference-list-menu')!;
|
||||
queryElems(elBranchMenu, '.item:not(.no-select)', (el) => el.addEventListener('click', async function (e) {
|
||||
e.preventDefault();
|
||||
const selectedValue = this.getAttribute('data-id')!; // eg: "refs/heads/my-branch"
|
||||
const selectedText = this.getAttribute('data-name'); // eg: "my-branch"
|
||||
|
||||
// the issue sidebar sets "urlUpdateIssueRef" for the dropdown
|
||||
if (urlUpdateIssueRef) {
|
||||
// for existing issue, send request to update issue ref, and reload page
|
||||
try {
|
||||
@ -30,23 +32,26 @@ function initBranchSelector() {
|
||||
}));
|
||||
}
|
||||
|
||||
function initRepoIssueDue() {
|
||||
const form = document.querySelector<HTMLFormElement>('.issue-due-form');
|
||||
function initRepoIssueDue(elSidebar: HTMLElement) {
|
||||
const form = elSidebar.querySelector<HTMLFormElement>('.issue-due-form');
|
||||
if (!form) return;
|
||||
const deadline = form.querySelector<HTMLInputElement>('input[name=deadline]')!;
|
||||
document.querySelector('.issue-due-edit')?.addEventListener('click', () => {
|
||||
elSidebar.querySelector('.issue-due-edit')?.addEventListener('click', () => {
|
||||
toggleElem(form);
|
||||
});
|
||||
document.querySelector('.issue-due-remove')?.addEventListener('click', () => {
|
||||
elSidebar.querySelector('.issue-due-remove')?.addEventListener('click', () => {
|
||||
deadline.value = '';
|
||||
form.dispatchEvent(new Event('submit', {cancelable: true, bubbles: true}));
|
||||
});
|
||||
}
|
||||
|
||||
export function initRepoIssueSidebar() {
|
||||
initBranchSelector();
|
||||
initRepoIssueDue();
|
||||
// FIXME: legacy dirty design, the dropdown is reused on Actions page
|
||||
registerGlobalInitFunc('initSelectBranchDropdown', initBranchSelector);
|
||||
|
||||
// init the combo list: a dropdown for selecting items, and a list for showing selected items and related actions
|
||||
queryElems<HTMLElement>(document, '.issue-sidebar-combo', (el) => new IssueSidebarComboList(el).init());
|
||||
registerGlobalInitFunc('initRepoIssueSidebar', (elSidebar) => {
|
||||
initRepoIssueDue(elSidebar);
|
||||
// init the combo list: a dropdown for selecting items, and a list for showing selected items and related actions
|
||||
queryElems(elSidebar, '.issue-sidebar-combo', (el) => new IssueSidebarComboList(el).init());
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user