mirror of https://github.com/go-gitea/gitea.git
Enable Typescript `noImplicitThis` (#33250)
- Enable https://www.typescriptlang.org/tsconfig/#noImplicitThis - Wrap Vue Template-Syntax SFCs in [`defineComponent`](https://vuejs.org/api/general#definecomponent) which makes type inference and linter work better - Move `createApp` calls outside the SFCs into separate files - Use [`PropType`](https://vuejs.org/api/utility-types#proptype-t) where appropriate - Some top-level component properties changed order as dictated by the linter - Fix all tsc and lint issues that popped up during these refactorspull/33276/head^2
parent
b15d01b0ce
commit
4b21a6c792
|
@ -23,6 +23,7 @@
|
||||||
"stripInternal": true,
|
"stripInternal": true,
|
||||||
"strict": false,
|
"strict": false,
|
||||||
"strictFunctionTypes": true,
|
"strictFunctionTypes": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"noUnusedParameters": true,
|
"noUnusedParameters": true,
|
||||||
"noPropertyAccessFromIndexSignature": false,
|
"noPropertyAccessFromIndexSignature": false,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {createApp, nextTick} from 'vue';
|
import {nextTick, defineComponent} from 'vue';
|
||||||
import {SvgIcon} from '../svg.ts';
|
import {SvgIcon} from '../svg.ts';
|
||||||
import {GET} from '../modules/fetch.ts';
|
import {GET} from '../modules/fetch.ts';
|
||||||
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
import {fomanticQuery} from '../modules/fomantic/base.ts';
|
||||||
|
@ -24,7 +24,7 @@ const commitStatus: CommitStatusMap = {
|
||||||
warning: {name: 'gitea-exclamation', color: 'yellow'},
|
warning: {name: 'gitea-exclamation', color: 'yellow'},
|
||||||
};
|
};
|
||||||
|
|
||||||
const sfc = {
|
export default defineComponent({
|
||||||
components: {SvgIcon},
|
components: {SvgIcon},
|
||||||
data() {
|
data() {
|
||||||
const params = new URLSearchParams(window.location.search);
|
const params = new URLSearchParams(window.location.search);
|
||||||
|
@ -335,16 +335,8 @@ const sfc = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
export function initDashboardRepoList() {
|
|
||||||
const el = document.querySelector('#dashboard-repo-list');
|
|
||||||
if (el) {
|
|
||||||
createApp(sfc).mount(el);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default sfc; // activate the IDE's Vue plugin
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import {defineComponent} from 'vue';
|
||||||
import {SvgIcon} from '../svg.ts';
|
import {SvgIcon} from '../svg.ts';
|
||||||
import {GET} from '../modules/fetch.ts';
|
import {GET} from '../modules/fetch.ts';
|
||||||
import {generateAriaId} from '../modules/fomantic/base.ts';
|
import {generateAriaId} from '../modules/fomantic/base.ts';
|
||||||
|
|
||||||
export default {
|
export default defineComponent({
|
||||||
components: {SvgIcon},
|
components: {SvgIcon},
|
||||||
data: () => {
|
data: () => {
|
||||||
const el = document.querySelector('#diff-commit-select');
|
const el = document.querySelector('#diff-commit-select');
|
||||||
|
@ -55,11 +56,11 @@ export default {
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case 'ArrowDown': // select next element
|
case 'ArrowDown': // select next element
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.focusElem(item.nextElementSibling, item);
|
this.focusElem(item.nextElementSibling as HTMLElement, item);
|
||||||
break;
|
break;
|
||||||
case 'ArrowUp': // select previous element
|
case 'ArrowUp': // select previous element
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.focusElem(item.previousElementSibling, item);
|
this.focusElem(item.previousElementSibling as HTMLElement, item);
|
||||||
break;
|
break;
|
||||||
case 'Escape': // close menu
|
case 'Escape': // close menu
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
@ -118,9 +119,9 @@ export default {
|
||||||
// set correct tabindex to allow easier navigation
|
// set correct tabindex to allow easier navigation
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.menuVisible) {
|
if (this.menuVisible) {
|
||||||
this.focusElem(this.$refs.showAllChanges, this.$refs.expandBtn);
|
this.focusElem(this.$refs.showAllChanges as HTMLElement, this.$refs.expandBtn as HTMLElement);
|
||||||
} else {
|
} else {
|
||||||
this.focusElem(this.$refs.expandBtn, this.$refs.showAllChanges);
|
this.focusElem(this.$refs.expandBtn as HTMLElement, this.$refs.showAllChanges as HTMLElement);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -188,7 +189,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="ui scrolling dropdown custom diff-commit-selector">
|
<div class="ui scrolling dropdown custom diff-commit-selector">
|
||||||
|
|
|
@ -17,7 +17,7 @@ function toggleFileList() {
|
||||||
store.fileListIsVisible = !store.fileListIsVisible;
|
store.fileListIsVisible = !store.fileListIsVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
function diffTypeToString(pType) {
|
function diffTypeToString(pType: number) {
|
||||||
const diffTypes = {
|
const diffTypes = {
|
||||||
1: 'add',
|
1: 'add',
|
||||||
2: 'modify',
|
2: 'modify',
|
||||||
|
@ -28,7 +28,7 @@ function diffTypeToString(pType) {
|
||||||
return diffTypes[pType];
|
return diffTypes[pType];
|
||||||
}
|
}
|
||||||
|
|
||||||
function diffStatsWidth(adds, dels) {
|
function diffStatsWidth(adds: number, dels: number) {
|
||||||
return `${adds / (adds + dels) * 100}%`;
|
return `${adds / (adds + dels) * 100}%`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ const fileTree = computed(() => {
|
||||||
parent = newParent;
|
parent = newParent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const mergeChildIfOnlyOneDir = (entries) => {
|
const mergeChildIfOnlyOneDir = (entries: Array<Record<string, any>>) => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (entry.children) {
|
if (entry.children) {
|
||||||
mergeChildIfOnlyOneDir(entry.children);
|
mergeChildIfOnlyOneDir(entry.children);
|
||||||
|
@ -110,13 +110,13 @@ function toggleVisibility() {
|
||||||
updateVisibility(!store.fileTreeIsVisible);
|
updateVisibility(!store.fileTreeIsVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVisibility(visible) {
|
function updateVisibility(visible: boolean) {
|
||||||
store.fileTreeIsVisible = visible;
|
store.fileTreeIsVisible = visible;
|
||||||
localStorage.setItem(LOCAL_STORAGE_KEY, store.fileTreeIsVisible);
|
localStorage.setItem(LOCAL_STORAGE_KEY, store.fileTreeIsVisible);
|
||||||
updateState(store.fileTreeIsVisible);
|
updateState(store.fileTreeIsVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateState(visible) {
|
function updateState(visible: boolean) {
|
||||||
const btn = document.querySelector('.diff-toggle-file-tree-button');
|
const btn = document.querySelector('.diff-toggle-file-tree-button');
|
||||||
const [toShow, toHide] = btn.querySelectorAll('.icon');
|
const [toShow, toHide] = btn.querySelectorAll('.icon');
|
||||||
const tree = document.querySelector('#diff-file-tree');
|
const tree = document.querySelector('#diff-file-tree');
|
||||||
|
|
|
@ -25,7 +25,7 @@ defineProps<{
|
||||||
const store = diffTreeStore();
|
const store = diffTreeStore();
|
||||||
const collapsed = ref(false);
|
const collapsed = ref(false);
|
||||||
|
|
||||||
function getIconForDiffType(pType) {
|
function getIconForDiffType(pType: number) {
|
||||||
const diffTypes = {
|
const diffTypes = {
|
||||||
1: {name: 'octicon-diff-added', classes: ['text', 'green']},
|
1: {name: 'octicon-diff-added', classes: ['text', 'green']},
|
||||||
2: {name: 'octicon-diff-modified', classes: ['text', 'yellow']},
|
2: {name: 'octicon-diff-modified', classes: ['text', 'yellow']},
|
||||||
|
@ -36,7 +36,7 @@ function getIconForDiffType(pType) {
|
||||||
return diffTypes[pType];
|
return diffTypes[pType];
|
||||||
}
|
}
|
||||||
|
|
||||||
function fileIcon(file) {
|
function fileIcon(file: File) {
|
||||||
if (file.IsSubmodule) {
|
if (file.IsSubmodule) {
|
||||||
return 'octicon-file-submodule';
|
return 'octicon-file-submodule';
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ function toggleActionForm(show: boolean) {
|
||||||
mergeMessageFieldValue.value = mergeStyleDetail.value.mergeMessageFieldText;
|
mergeMessageFieldValue.value = mergeStyleDetail.value.mergeMessageFieldText;
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchMergeStyle(name, autoMerge = false) {
|
function switchMergeStyle(name: string, autoMerge = false) {
|
||||||
mergeStyle.value = name;
|
mergeStyle.value = name;
|
||||||
autoMergeWhenSucceed.value = autoMerge;
|
autoMergeWhenSucceed.value = autoMerge;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {SvgIcon} from '../svg.ts';
|
import {SvgIcon} from '../svg.ts';
|
||||||
import ActionRunStatus from './ActionRunStatus.vue';
|
import ActionRunStatus from './ActionRunStatus.vue';
|
||||||
import {createApp} from 'vue';
|
import {defineComponent, type PropType} from 'vue';
|
||||||
import {createElementFromAttrs, toggleElem} from '../utils/dom.ts';
|
import {createElementFromAttrs, toggleElem} from '../utils/dom.ts';
|
||||||
import {formatDatetime} from '../utils/time.ts';
|
import {formatDatetime} from '../utils/time.ts';
|
||||||
import {renderAnsi} from '../render/ansi.ts';
|
import {renderAnsi} from '../render/ansi.ts';
|
||||||
|
@ -38,7 +38,7 @@ function parseLineCommand(line: LogLine): LogLineCommand | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLogElementInViewport(el: HTMLElement): boolean {
|
function isLogElementInViewport(el: Element): boolean {
|
||||||
const rect = el.getBoundingClientRect();
|
const rect = el.getBoundingClientRect();
|
||||||
return rect.top >= 0 && rect.bottom <= window.innerHeight; // only check height but not width
|
return rect.top >= 0 && rect.bottom <= window.innerHeight; // only check height but not width
|
||||||
}
|
}
|
||||||
|
@ -57,25 +57,28 @@ function getLocaleStorageOptions(): LocaleStorageOptions {
|
||||||
return {autoScroll: true, expandRunning: false};
|
return {autoScroll: true, expandRunning: false};
|
||||||
}
|
}
|
||||||
|
|
||||||
const sfc = {
|
export default defineComponent({
|
||||||
name: 'RepoActionView',
|
name: 'RepoActionView',
|
||||||
components: {
|
components: {
|
||||||
SvgIcon,
|
SvgIcon,
|
||||||
ActionRunStatus,
|
ActionRunStatus,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
runIndex: String,
|
runIndex: {
|
||||||
jobIndex: String,
|
type: String,
|
||||||
actionsURL: String,
|
default: '',
|
||||||
locale: Object,
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
optionAlwaysAutoScroll() {
|
|
||||||
this.saveLocaleStorageOptions();
|
|
||||||
},
|
},
|
||||||
optionAlwaysExpandRunning() {
|
jobIndex: {
|
||||||
this.saveLocaleStorageOptions();
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
actionsURL: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
locale: {
|
||||||
|
type: Object as PropType<Record<string, string>>,
|
||||||
|
default: null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -102,10 +105,11 @@ const sfc = {
|
||||||
link: '',
|
link: '',
|
||||||
title: '',
|
title: '',
|
||||||
titleHTML: '',
|
titleHTML: '',
|
||||||
status: '',
|
status: 'unknown' as RunStatus,
|
||||||
canCancel: false,
|
canCancel: false,
|
||||||
canApprove: false,
|
canApprove: false,
|
||||||
canRerun: false,
|
canRerun: false,
|
||||||
|
canDeleteArtifact: false,
|
||||||
done: false,
|
done: false,
|
||||||
workflowID: '',
|
workflowID: '',
|
||||||
workflowLink: '',
|
workflowLink: '',
|
||||||
|
@ -131,6 +135,7 @@ const sfc = {
|
||||||
branch: {
|
branch: {
|
||||||
name: '',
|
name: '',
|
||||||
link: '',
|
link: '',
|
||||||
|
isDeleted: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -148,7 +153,16 @@ const sfc = {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
async mounted() {
|
watch: {
|
||||||
|
optionAlwaysAutoScroll() {
|
||||||
|
this.saveLocaleStorageOptions();
|
||||||
|
},
|
||||||
|
optionAlwaysExpandRunning() {
|
||||||
|
this.saveLocaleStorageOptions();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async mounted() { // eslint-disable-line @typescript-eslint/no-misused-promises
|
||||||
// load job data and then auto-reload periodically
|
// load job data and then auto-reload periodically
|
||||||
// need to await first loadJob so this.currentJobStepsStates is initialized and can be used in hashChangeListener
|
// need to await first loadJob so this.currentJobStepsStates is initialized and can be used in hashChangeListener
|
||||||
await this.loadJob();
|
await this.loadJob();
|
||||||
|
@ -186,6 +200,7 @@ const sfc = {
|
||||||
// get the active logs container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group`
|
// get the active logs container element, either the `job-step-logs` or the `job-log-list` in the `job-log-group`
|
||||||
getActiveLogsContainer(stepIndex: number): HTMLElement {
|
getActiveLogsContainer(stepIndex: number): HTMLElement {
|
||||||
const el = this.getJobStepLogsContainer(stepIndex);
|
const el = this.getJobStepLogsContainer(stepIndex);
|
||||||
|
// @ts-expect-error - _stepLogsActiveContainer is a custom property
|
||||||
return el._stepLogsActiveContainer ?? el;
|
return el._stepLogsActiveContainer ?? el;
|
||||||
},
|
},
|
||||||
// begin a log group
|
// begin a log group
|
||||||
|
@ -263,7 +278,7 @@ const sfc = {
|
||||||
const el = this.getJobStepLogsContainer(stepIndex);
|
const el = this.getJobStepLogsContainer(stepIndex);
|
||||||
// if the logs container is empty, then auto-scroll if the step is expanded
|
// if the logs container is empty, then auto-scroll if the step is expanded
|
||||||
if (!el.lastChild) return this.currentJobStepsStates[stepIndex].expanded;
|
if (!el.lastChild) return this.currentJobStepsStates[stepIndex].expanded;
|
||||||
return isLogElementInViewport(el.lastChild);
|
return isLogElementInViewport(el.lastChild as Element);
|
||||||
},
|
},
|
||||||
|
|
||||||
appendLogs(stepIndex: number, startTime: number, logLines: LogLine[]) {
|
appendLogs(stepIndex: number, startTime: number, logLines: LogLine[]) {
|
||||||
|
@ -380,7 +395,7 @@ const sfc = {
|
||||||
|
|
||||||
toggleTimeDisplay(type: string) {
|
toggleTimeDisplay(type: string) {
|
||||||
this.timeVisible[`log-time-${type}`] = !this.timeVisible[`log-time-${type}`];
|
this.timeVisible[`log-time-${type}`] = !this.timeVisible[`log-time-${type}`];
|
||||||
for (const el of this.$refs.steps.querySelectorAll(`.log-time-${type}`)) {
|
for (const el of (this.$refs.steps as HTMLElement).querySelectorAll(`.log-time-${type}`)) {
|
||||||
toggleElem(el, this.timeVisible[`log-time-${type}`]);
|
toggleElem(el, this.timeVisible[`log-time-${type}`]);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -414,59 +429,12 @@ const sfc = {
|
||||||
// so logline can be selected by querySelector
|
// so logline can be selected by querySelector
|
||||||
await this.loadJob();
|
await this.loadJob();
|
||||||
}
|
}
|
||||||
const logLine = this.$refs.steps.querySelector(selectedLogStep);
|
const logLine = (this.$refs.steps as HTMLElement).querySelector(selectedLogStep);
|
||||||
if (!logLine) return;
|
if (!logLine) return;
|
||||||
logLine.querySelector('.line-num').click();
|
logLine.querySelector<HTMLAnchorElement>('.line-num').click();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
export default sfc;
|
|
||||||
|
|
||||||
export function initRepositoryActionView() {
|
|
||||||
const el = document.querySelector('#repo-action-view');
|
|
||||||
if (!el) return;
|
|
||||||
|
|
||||||
// TODO: the parent element's full height doesn't work well now,
|
|
||||||
// but we can not pollute the global style at the moment, only fix the height problem for pages with this component
|
|
||||||
const parentFullHeight = document.querySelector<HTMLElement>('body > div.full.height');
|
|
||||||
if (parentFullHeight) parentFullHeight.style.paddingBottom = '0';
|
|
||||||
|
|
||||||
const view = createApp(sfc, {
|
|
||||||
runIndex: el.getAttribute('data-run-index'),
|
|
||||||
jobIndex: el.getAttribute('data-job-index'),
|
|
||||||
actionsURL: el.getAttribute('data-actions-url'),
|
|
||||||
locale: {
|
|
||||||
approve: el.getAttribute('data-locale-approve'),
|
|
||||||
cancel: el.getAttribute('data-locale-cancel'),
|
|
||||||
rerun: el.getAttribute('data-locale-rerun'),
|
|
||||||
rerun_all: el.getAttribute('data-locale-rerun-all'),
|
|
||||||
scheduled: el.getAttribute('data-locale-runs-scheduled'),
|
|
||||||
commit: el.getAttribute('data-locale-runs-commit'),
|
|
||||||
pushedBy: el.getAttribute('data-locale-runs-pushed-by'),
|
|
||||||
artifactsTitle: el.getAttribute('data-locale-artifacts-title'),
|
|
||||||
areYouSure: el.getAttribute('data-locale-are-you-sure'),
|
|
||||||
confirmDeleteArtifact: el.getAttribute('data-locale-confirm-delete-artifact'),
|
|
||||||
showTimeStamps: el.getAttribute('data-locale-show-timestamps'),
|
|
||||||
showLogSeconds: el.getAttribute('data-locale-show-log-seconds'),
|
|
||||||
showFullScreen: el.getAttribute('data-locale-show-full-screen'),
|
|
||||||
downloadLogs: el.getAttribute('data-locale-download-logs'),
|
|
||||||
status: {
|
|
||||||
unknown: el.getAttribute('data-locale-status-unknown'),
|
|
||||||
waiting: el.getAttribute('data-locale-status-waiting'),
|
|
||||||
running: el.getAttribute('data-locale-status-running'),
|
|
||||||
success: el.getAttribute('data-locale-status-success'),
|
|
||||||
failure: el.getAttribute('data-locale-status-failure'),
|
|
||||||
cancelled: el.getAttribute('data-locale-status-cancelled'),
|
|
||||||
skipped: el.getAttribute('data-locale-status-skipped'),
|
|
||||||
blocked: el.getAttribute('data-locale-status-blocked'),
|
|
||||||
},
|
|
||||||
logsAlwaysAutoScroll: el.getAttribute('data-locale-logs-always-auto-scroll'),
|
|
||||||
logsAlwaysExpandRunning: el.getAttribute('data-locale-logs-always-expand-running'),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
view.mount(el);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="ui container action-view-container">
|
<div class="ui container action-view-container">
|
||||||
|
|
|
@ -8,13 +8,15 @@ const colors = ref({
|
||||||
textAltColor: 'white',
|
textAltColor: 'white',
|
||||||
});
|
});
|
||||||
|
|
||||||
// possible keys:
|
type ActivityAuthorData = {
|
||||||
// * avatar_link: (...)
|
avatar_link: string;
|
||||||
// * commits: (...)
|
commits: number;
|
||||||
// * home_link: (...)
|
home_link: string;
|
||||||
// * login: (...)
|
login: string;
|
||||||
// * name: (...)
|
name: string;
|
||||||
const activityTopAuthors = window.config.pageData.repoActivityTopAuthors || [];
|
}
|
||||||
|
|
||||||
|
const activityTopAuthors: Array<ActivityAuthorData> = window.config.pageData.repoActivityTopAuthors || [];
|
||||||
|
|
||||||
const graphPoints = computed(() => {
|
const graphPoints = computed(() => {
|
||||||
return activityTopAuthors.map((item) => {
|
return activityTopAuthors.map((item) => {
|
||||||
|
@ -26,7 +28,7 @@ const graphPoints = computed(() => {
|
||||||
});
|
});
|
||||||
|
|
||||||
const graphAuthors = computed(() => {
|
const graphAuthors = computed(() => {
|
||||||
return activityTopAuthors.map((item, idx) => {
|
return activityTopAuthors.map((item, idx: number) => {
|
||||||
return {
|
return {
|
||||||
position: idx + 1,
|
position: idx + 1,
|
||||||
...item,
|
...item,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {nextTick} from 'vue';
|
import {defineComponent, nextTick} from 'vue';
|
||||||
import {SvgIcon} from '../svg.ts';
|
import {SvgIcon} from '../svg.ts';
|
||||||
import {showErrorToast} from '../modules/toast.ts';
|
import {showErrorToast} from '../modules/toast.ts';
|
||||||
import {GET} from '../modules/fetch.ts';
|
import {GET} from '../modules/fetch.ts';
|
||||||
|
@ -17,51 +17,11 @@ type SelectedTab = 'branches' | 'tags';
|
||||||
|
|
||||||
type TabLoadingStates = Record<SelectedTab, '' | 'loading' | 'done'>
|
type TabLoadingStates = Record<SelectedTab, '' | 'loading' | 'done'>
|
||||||
|
|
||||||
const sfc = {
|
export default defineComponent({
|
||||||
components: {SvgIcon},
|
components: {SvgIcon},
|
||||||
props: {
|
props: {
|
||||||
elRoot: HTMLElement,
|
elRoot: HTMLElement,
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
searchFieldPlaceholder() {
|
|
||||||
return this.selectedTab === 'branches' ? this.textFilterBranch : this.textFilterTag;
|
|
||||||
},
|
|
||||||
filteredItems(): ListItem[] {
|
|
||||||
const searchTermLower = this.searchTerm.toLowerCase();
|
|
||||||
const items = this.allItems.filter((item: ListItem) => {
|
|
||||||
const typeMatched = (this.selectedTab === 'branches' && item.refType === 'branch') || (this.selectedTab === 'tags' && item.refType === 'tag');
|
|
||||||
if (!typeMatched) return false;
|
|
||||||
if (!this.searchTerm) return true; // match all
|
|
||||||
return item.refShortName.toLowerCase().includes(searchTermLower);
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO: fix this anti-pattern: side-effects-in-computed-properties
|
|
||||||
this.activeItemIndex = !items.length && this.showCreateNewRef ? 0 : -1;
|
|
||||||
return items;
|
|
||||||
},
|
|
||||||
showNoResults() {
|
|
||||||
if (this.tabLoadingStates[this.selectedTab] !== 'done') return false;
|
|
||||||
return !this.filteredItems.length && !this.showCreateNewRef;
|
|
||||||
},
|
|
||||||
showCreateNewRef() {
|
|
||||||
if (!this.allowCreateNewRef || !this.searchTerm) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !this.allItems.filter((item: ListItem) => {
|
|
||||||
return item.refShortName === this.searchTerm; // FIXME: not quite right here, it mixes "branch" and "tag" names
|
|
||||||
}).length;
|
|
||||||
},
|
|
||||||
createNewRefFormActionUrl() {
|
|
||||||
return `${this.currentRepoLink}/branches/_new/${this.currentRefType}/${pathEscapeSegments(this.currentRefShortName)}`;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
menuVisible(visible: boolean) {
|
|
||||||
if (!visible) return;
|
|
||||||
this.focusSearchField();
|
|
||||||
this.loadTabItems();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
data() {
|
data() {
|
||||||
const shouldShowTabBranches = this.elRoot.getAttribute('data-show-tab-branches') === 'true';
|
const shouldShowTabBranches = this.elRoot.getAttribute('data-show-tab-branches') === 'true';
|
||||||
return {
|
return {
|
||||||
|
@ -89,7 +49,7 @@ const sfc = {
|
||||||
currentRepoDefaultBranch: this.elRoot.getAttribute('data-current-repo-default-branch'),
|
currentRepoDefaultBranch: this.elRoot.getAttribute('data-current-repo-default-branch'),
|
||||||
currentRepoLink: this.elRoot.getAttribute('data-current-repo-link'),
|
currentRepoLink: this.elRoot.getAttribute('data-current-repo-link'),
|
||||||
currentTreePath: this.elRoot.getAttribute('data-current-tree-path'),
|
currentTreePath: this.elRoot.getAttribute('data-current-tree-path'),
|
||||||
currentRefType: this.elRoot.getAttribute('data-current-ref-type'),
|
currentRefType: this.elRoot.getAttribute('data-current-ref-type') as GitRefType,
|
||||||
currentRefShortName: this.elRoot.getAttribute('data-current-ref-short-name'),
|
currentRefShortName: this.elRoot.getAttribute('data-current-ref-short-name'),
|
||||||
|
|
||||||
refLinkTemplate: this.elRoot.getAttribute('data-ref-link-template'),
|
refLinkTemplate: this.elRoot.getAttribute('data-ref-link-template'),
|
||||||
|
@ -102,6 +62,46 @@ const sfc = {
|
||||||
enableFeed: this.elRoot.getAttribute('data-enable-feed') === 'true',
|
enableFeed: this.elRoot.getAttribute('data-enable-feed') === 'true',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
searchFieldPlaceholder() {
|
||||||
|
return this.selectedTab === 'branches' ? this.textFilterBranch : this.textFilterTag;
|
||||||
|
},
|
||||||
|
filteredItems(): ListItem[] {
|
||||||
|
const searchTermLower = this.searchTerm.toLowerCase();
|
||||||
|
const items = this.allItems.filter((item: ListItem) => {
|
||||||
|
const typeMatched = (this.selectedTab === 'branches' && item.refType === 'branch') || (this.selectedTab === 'tags' && item.refType === 'tag');
|
||||||
|
if (!typeMatched) return false;
|
||||||
|
if (!this.searchTerm) return true; // match all
|
||||||
|
return item.refShortName.toLowerCase().includes(searchTermLower);
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: fix this anti-pattern: side-effects-in-computed-properties
|
||||||
|
this.activeItemIndex = !items.length && this.showCreateNewRef ? 0 : -1; // eslint-disable-line vue/no-side-effects-in-computed-properties
|
||||||
|
return items;
|
||||||
|
},
|
||||||
|
showNoResults() {
|
||||||
|
if (this.tabLoadingStates[this.selectedTab] !== 'done') return false;
|
||||||
|
return !this.filteredItems.length && !this.showCreateNewRef;
|
||||||
|
},
|
||||||
|
showCreateNewRef() {
|
||||||
|
if (!this.allowCreateNewRef || !this.searchTerm) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !this.allItems.filter((item: ListItem) => {
|
||||||
|
return item.refShortName === this.searchTerm; // FIXME: not quite right here, it mixes "branch" and "tag" names
|
||||||
|
}).length;
|
||||||
|
},
|
||||||
|
createNewRefFormActionUrl() {
|
||||||
|
return `${this.currentRepoLink}/branches/_new/${this.currentRefType}/${pathEscapeSegments(this.currentRefShortName)}`;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
menuVisible(visible: boolean) {
|
||||||
|
if (!visible) return;
|
||||||
|
this.focusSearchField();
|
||||||
|
this.loadTabItems();
|
||||||
|
},
|
||||||
|
},
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
document.body.addEventListener('click', (e) => {
|
document.body.addEventListener('click', (e) => {
|
||||||
if (this.$el.contains(e.target)) return;
|
if (this.$el.contains(e.target)) return;
|
||||||
|
@ -139,11 +139,11 @@ const sfc = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
createNewRef() {
|
createNewRef() {
|
||||||
this.$refs.createNewRefForm?.submit();
|
(this.$refs.createNewRefForm as HTMLFormElement)?.submit();
|
||||||
},
|
},
|
||||||
focusSearchField() {
|
focusSearchField() {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
this.$refs.searchField.focus();
|
(this.$refs.searchField as HTMLInputElement).focus();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
getSelectedIndexInFiltered() {
|
getSelectedIndexInFiltered() {
|
||||||
|
@ -154,6 +154,7 @@ const sfc = {
|
||||||
},
|
},
|
||||||
getActiveItem() {
|
getActiveItem() {
|
||||||
const el = this.$refs[`listItem${this.activeItemIndex}`]; // eslint-disable-line no-jquery/variable-pattern
|
const el = this.$refs[`listItem${this.activeItemIndex}`]; // eslint-disable-line no-jquery/variable-pattern
|
||||||
|
// @ts-expect-error - el is unknown type
|
||||||
return (el && el.length) ? el[0] : null;
|
return (el && el.length) ? el[0] : null;
|
||||||
},
|
},
|
||||||
keydown(e) {
|
keydown(e) {
|
||||||
|
@ -212,9 +213,7 @@ const sfc = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
export default sfc; // activate IDE's Vue plugin
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="ui dropdown custom branch-selector-dropdown ellipsis-items-nowrap">
|
<div class="ui dropdown custom branch-selector-dropdown ellipsis-items-nowrap">
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import {defineComponent, type PropType} from 'vue';
|
||||||
import {SvgIcon} from '../svg.ts';
|
import {SvgIcon} from '../svg.ts';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import {
|
import {
|
||||||
|
@ -56,11 +57,11 @@ Chart.register(
|
||||||
customEventListener,
|
customEventListener,
|
||||||
);
|
);
|
||||||
|
|
||||||
export default {
|
export default defineComponent({
|
||||||
components: {ChartLine, SvgIcon},
|
components: {ChartLine, SvgIcon},
|
||||||
props: {
|
props: {
|
||||||
locale: {
|
locale: {
|
||||||
type: Object,
|
type: Object as PropType<Record<string, any>>,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
repoLink: {
|
repoLink: {
|
||||||
|
@ -88,7 +89,7 @@ export default {
|
||||||
this.fetchGraphData();
|
this.fetchGraphData();
|
||||||
|
|
||||||
fomanticQuery('#repo-contributors').dropdown({
|
fomanticQuery('#repo-contributors').dropdown({
|
||||||
onChange: (val) => {
|
onChange: (val: string) => {
|
||||||
this.xAxisMin = this.xAxisStart;
|
this.xAxisMin = this.xAxisStart;
|
||||||
this.xAxisMax = this.xAxisEnd;
|
this.xAxisMax = this.xAxisEnd;
|
||||||
this.type = val;
|
this.type = val;
|
||||||
|
@ -320,7 +321,7 @@ export default {
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -6,7 +6,7 @@ export function initCommonOrganization() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector('.organization.settings.options #org_name')?.addEventListener('input', function () {
|
document.querySelector<HTMLInputElement>('.organization.settings.options #org_name')?.addEventListener('input', function () {
|
||||||
const nameChanged = this.value.toLowerCase() !== this.getAttribute('data-org-name').toLowerCase();
|
const nameChanged = this.value.toLowerCase() !== this.getAttribute('data-org-name').toLowerCase();
|
||||||
toggleElem('#org-name-change-prompt', nameChanged);
|
toggleElem('#org-name-change-prompt', nameChanged);
|
||||||
});
|
});
|
||||||
|
|
|
@ -6,7 +6,7 @@ export function initCompWebHookEditor() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const input of document.querySelectorAll('.events.checkbox input')) {
|
for (const input of document.querySelectorAll<HTMLInputElement>('.events.checkbox input')) {
|
||||||
input.addEventListener('change', function () {
|
input.addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
showElem('.events.fields');
|
showElem('.events.fields');
|
||||||
|
@ -14,7 +14,7 @@ export function initCompWebHookEditor() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const input of document.querySelectorAll('.non-events.checkbox input')) {
|
for (const input of document.querySelectorAll<HTMLInputElement>('.non-events.checkbox input')) {
|
||||||
input.addEventListener('change', function () {
|
input.addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
hideElem('.events.fields');
|
hideElem('.events.fields');
|
||||||
|
@ -34,7 +34,7 @@ export function initCompWebHookEditor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test delivery
|
// Test delivery
|
||||||
document.querySelector('#test-delivery')?.addEventListener('click', async function () {
|
document.querySelector<HTMLButtonElement>('#test-delivery')?.addEventListener('click', async function () {
|
||||||
this.classList.add('is-loading', 'disabled');
|
this.classList.add('is-loading', 'disabled');
|
||||||
await POST(this.getAttribute('data-link'));
|
await POST(this.getAttribute('data-link'));
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import {createApp} from 'vue';
|
||||||
|
import DashboardRepoList from '../components/DashboardRepoList.vue';
|
||||||
|
|
||||||
|
export function initDashboardRepoList() {
|
||||||
|
const el = document.querySelector('#dashboard-repo-list');
|
||||||
|
if (el) {
|
||||||
|
createApp(DashboardRepoList).mount(el);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ function initPreInstall() {
|
||||||
const dbName = document.querySelector<HTMLInputElement>('#db_name');
|
const dbName = document.querySelector<HTMLInputElement>('#db_name');
|
||||||
|
|
||||||
// Database type change detection.
|
// Database type change detection.
|
||||||
document.querySelector('#db_type').addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#db_type').addEventListener('change', function () {
|
||||||
const dbType = this.value;
|
const dbType = this.value;
|
||||||
hideElem('div[data-db-setting-for]');
|
hideElem('div[data-db-setting-for]');
|
||||||
showElem(`div[data-db-setting-for=${dbType}]`);
|
showElem(`div[data-db-setting-for=${dbType}]`);
|
||||||
|
@ -59,26 +59,26 @@ function initPreInstall() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: better handling of exclusive relations.
|
// TODO: better handling of exclusive relations.
|
||||||
document.querySelector('#offline-mode input').addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#offline-mode input').addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
document.querySelector<HTMLInputElement>('#disable-gravatar input').checked = true;
|
document.querySelector<HTMLInputElement>('#disable-gravatar input').checked = true;
|
||||||
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input').checked = false;
|
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input').checked = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.querySelector('#disable-gravatar input').addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#disable-gravatar input').addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input').checked = false;
|
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input').checked = false;
|
||||||
} else {
|
} else {
|
||||||
document.querySelector<HTMLInputElement>('#offline-mode input').checked = false;
|
document.querySelector<HTMLInputElement>('#offline-mode input').checked = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.querySelector('#federated-avatar-lookup input').addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#federated-avatar-lookup input').addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
document.querySelector<HTMLInputElement>('#disable-gravatar input').checked = false;
|
document.querySelector<HTMLInputElement>('#disable-gravatar input').checked = false;
|
||||||
document.querySelector<HTMLInputElement>('#offline-mode input').checked = false;
|
document.querySelector<HTMLInputElement>('#offline-mode input').checked = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.querySelector('#enable-openid-signin input').addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#enable-openid-signin input').addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
if (!document.querySelector<HTMLInputElement>('#disable-registration input').checked) {
|
if (!document.querySelector<HTMLInputElement>('#disable-registration input').checked) {
|
||||||
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = true;
|
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = true;
|
||||||
|
@ -87,7 +87,7 @@ function initPreInstall() {
|
||||||
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = false;
|
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.querySelector('#disable-registration input').addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#disable-registration input').addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
document.querySelector<HTMLInputElement>('#enable-captcha input').checked = false;
|
document.querySelector<HTMLInputElement>('#enable-captcha input').checked = false;
|
||||||
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = false;
|
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = false;
|
||||||
|
@ -95,7 +95,7 @@ function initPreInstall() {
|
||||||
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = true;
|
document.querySelector<HTMLInputElement>('#enable-openid-signup input').checked = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.querySelector('#enable-captcha input').addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#enable-captcha input').addEventListener('change', function () {
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
document.querySelector<HTMLInputElement>('#disable-registration input').checked = false;
|
document.querySelector<HTMLInputElement>('#disable-registration input').checked = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ export function initViewedCheckboxListenerFor() {
|
||||||
|
|
||||||
// The checkbox consists of a div containing the real checkbox with its label and the CSRF token,
|
// The checkbox consists of a div containing the real checkbox with its label and the CSRF token,
|
||||||
// hence the actual checkbox first has to be found
|
// hence the actual checkbox first has to be found
|
||||||
const checkbox = form.querySelector('input[type=checkbox]');
|
const checkbox = form.querySelector<HTMLInputElement>('input[type=checkbox]');
|
||||||
checkbox.addEventListener('input', function() {
|
checkbox.addEventListener('input', function() {
|
||||||
// Mark the file as viewed visually - will especially change the background
|
// Mark the file as viewed visually - will especially change the background
|
||||||
if (this.checked) {
|
if (this.checked) {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
import {createApp} from 'vue';
|
||||||
|
import RepoActionView from '../components/RepoActionView.vue';
|
||||||
|
|
||||||
|
export function initRepositoryActionView() {
|
||||||
|
const el = document.querySelector('#repo-action-view');
|
||||||
|
if (!el) return;
|
||||||
|
|
||||||
|
// TODO: the parent element's full height doesn't work well now,
|
||||||
|
// but we can not pollute the global style at the moment, only fix the height problem for pages with this component
|
||||||
|
const parentFullHeight = document.querySelector<HTMLElement>('body > div.full.height');
|
||||||
|
if (parentFullHeight) parentFullHeight.style.paddingBottom = '0';
|
||||||
|
|
||||||
|
const view = createApp(RepoActionView, {
|
||||||
|
runIndex: el.getAttribute('data-run-index'),
|
||||||
|
jobIndex: el.getAttribute('data-job-index'),
|
||||||
|
actionsURL: el.getAttribute('data-actions-url'),
|
||||||
|
locale: {
|
||||||
|
approve: el.getAttribute('data-locale-approve'),
|
||||||
|
cancel: el.getAttribute('data-locale-cancel'),
|
||||||
|
rerun: el.getAttribute('data-locale-rerun'),
|
||||||
|
rerun_all: el.getAttribute('data-locale-rerun-all'),
|
||||||
|
scheduled: el.getAttribute('data-locale-runs-scheduled'),
|
||||||
|
commit: el.getAttribute('data-locale-runs-commit'),
|
||||||
|
pushedBy: el.getAttribute('data-locale-runs-pushed-by'),
|
||||||
|
artifactsTitle: el.getAttribute('data-locale-artifacts-title'),
|
||||||
|
areYouSure: el.getAttribute('data-locale-are-you-sure'),
|
||||||
|
confirmDeleteArtifact: el.getAttribute('data-locale-confirm-delete-artifact'),
|
||||||
|
showTimeStamps: el.getAttribute('data-locale-show-timestamps'),
|
||||||
|
showLogSeconds: el.getAttribute('data-locale-show-log-seconds'),
|
||||||
|
showFullScreen: el.getAttribute('data-locale-show-full-screen'),
|
||||||
|
downloadLogs: el.getAttribute('data-locale-download-logs'),
|
||||||
|
status: {
|
||||||
|
unknown: el.getAttribute('data-locale-status-unknown'),
|
||||||
|
waiting: el.getAttribute('data-locale-status-waiting'),
|
||||||
|
running: el.getAttribute('data-locale-status-running'),
|
||||||
|
success: el.getAttribute('data-locale-status-success'),
|
||||||
|
failure: el.getAttribute('data-locale-status-failure'),
|
||||||
|
cancelled: el.getAttribute('data-locale-status-cancelled'),
|
||||||
|
skipped: el.getAttribute('data-locale-status-skipped'),
|
||||||
|
blocked: el.getAttribute('data-locale-status-blocked'),
|
||||||
|
},
|
||||||
|
logsAlwaysAutoScroll: el.getAttribute('data-locale-logs-always-auto-scroll'),
|
||||||
|
logsAlwaysExpandRunning: el.getAttribute('data-locale-logs-always-expand-running'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
view.mount(el);
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ import {createTippy} from '../modules/tippy.ts';
|
||||||
import {toggleElem} from '../utils/dom.ts';
|
import {toggleElem} from '../utils/dom.ts';
|
||||||
|
|
||||||
export function initRepoEllipsisButton() {
|
export function initRepoEllipsisButton() {
|
||||||
for (const button of document.querySelectorAll('.js-toggle-commit-body')) {
|
for (const button of document.querySelectorAll<HTMLButtonElement>('.js-toggle-commit-body')) {
|
||||||
button.addEventListener('click', function (e) {
|
button.addEventListener('click', function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const expanded = this.getAttribute('aria-expanded') === 'true';
|
const expanded = this.getAttribute('aria-expanded') === 'true';
|
||||||
|
|
|
@ -89,7 +89,7 @@ export function initRepoTopicBar() {
|
||||||
url: `${appSubUrl}/explore/topics/search?q={query}`,
|
url: `${appSubUrl}/explore/topics/search?q={query}`,
|
||||||
throttle: 500,
|
throttle: 500,
|
||||||
cache: false,
|
cache: false,
|
||||||
onResponse(res) {
|
onResponse(this: any, res: any) {
|
||||||
const formattedResponse = {
|
const formattedResponse = {
|
||||||
success: false,
|
success: false,
|
||||||
results: [],
|
results: [],
|
||||||
|
|
|
@ -216,7 +216,7 @@ export function initRepoIssueCodeCommentCancel() {
|
||||||
|
|
||||||
export function initRepoPullRequestUpdate() {
|
export function initRepoPullRequestUpdate() {
|
||||||
// Pull Request update button
|
// Pull Request update button
|
||||||
const pullUpdateButton = document.querySelector('.update-button > button');
|
const pullUpdateButton = document.querySelector<HTMLButtonElement>('.update-button > button');
|
||||||
if (!pullUpdateButton) return;
|
if (!pullUpdateButton) return;
|
||||||
|
|
||||||
pullUpdateButton.addEventListener('click', async function (e) {
|
pullUpdateButton.addEventListener('click', async function (e) {
|
||||||
|
|
|
@ -79,21 +79,21 @@ function initRepoSettingsGitHook() {
|
||||||
function initRepoSettingsBranches() {
|
function initRepoSettingsBranches() {
|
||||||
if (!document.querySelector('.repository.settings.branches')) return;
|
if (!document.querySelector('.repository.settings.branches')) return;
|
||||||
|
|
||||||
for (const el of document.querySelectorAll('.toggle-target-enabled')) {
|
for (const el of document.querySelectorAll<HTMLInputElement>('.toggle-target-enabled')) {
|
||||||
el.addEventListener('change', function () {
|
el.addEventListener('change', function () {
|
||||||
const target = document.querySelector(this.getAttribute('data-target'));
|
const target = document.querySelector(this.getAttribute('data-target'));
|
||||||
target?.classList.toggle('disabled', !this.checked);
|
target?.classList.toggle('disabled', !this.checked);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const el of document.querySelectorAll('.toggle-target-disabled')) {
|
for (const el of document.querySelectorAll<HTMLInputElement>('.toggle-target-disabled')) {
|
||||||
el.addEventListener('change', function () {
|
el.addEventListener('change', function () {
|
||||||
const target = document.querySelector(this.getAttribute('data-target'));
|
const target = document.querySelector(this.getAttribute('data-target'));
|
||||||
if (this.checked) target?.classList.add('disabled'); // only disable, do not auto enable
|
if (this.checked) target?.classList.add('disabled'); // only disable, do not auto enable
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.querySelector('#dismiss_stale_approvals')?.addEventListener('change', function () {
|
document.querySelector<HTMLInputElement>('#dismiss_stale_approvals')?.addEventListener('change', function () {
|
||||||
document.querySelector('#ignore_stale_approvals_box')?.classList.toggle('disabled', this.checked);
|
document.querySelector('#ignore_stale_approvals_box')?.classList.toggle('disabled', this.checked);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
export function initSshKeyFormParser() {
|
export function initSshKeyFormParser() {
|
||||||
// Parse SSH Key
|
// Parse SSH Key
|
||||||
document.querySelector('#ssh-key-content')?.addEventListener('input', function () {
|
document.querySelector<HTMLTextAreaElement>('#ssh-key-content')?.addEventListener('input', function () {
|
||||||
const arrays = this.value.split(' ');
|
const arrays = this.value.split(' ');
|
||||||
const title = document.querySelector<HTMLInputElement>('#ssh-key-title');
|
const title = document.querySelector<HTMLInputElement>('#ssh-key-title');
|
||||||
if (!title.value && arrays.length === 3 && arrays[2] !== '') {
|
if (!title.value && arrays.length === 3 && arrays[2] !== '') {
|
||||||
|
|
|
@ -13,7 +13,7 @@ export function initUserSettings() {
|
||||||
|
|
||||||
initUserSettingsAvatarCropper();
|
initUserSettingsAvatarCropper();
|
||||||
|
|
||||||
const usernameInput = document.querySelector('#username');
|
const usernameInput = document.querySelector<HTMLInputElement>('#username');
|
||||||
if (!usernameInput) return;
|
if (!usernameInput) return;
|
||||||
usernameInput.addEventListener('input', function () {
|
usernameInput.addEventListener('input', function () {
|
||||||
const prompt = document.querySelector('#name-change-prompt');
|
const prompt = document.querySelector('#name-change-prompt');
|
||||||
|
|
|
@ -2,8 +2,7 @@
|
||||||
import './bootstrap.ts';
|
import './bootstrap.ts';
|
||||||
import './htmx.ts';
|
import './htmx.ts';
|
||||||
|
|
||||||
import {initDashboardRepoList} from './components/DashboardRepoList.vue';
|
import {initDashboardRepoList} from './features/dashboard.ts';
|
||||||
|
|
||||||
import {initGlobalCopyToClipboardListener} from './features/clipboard.ts';
|
import {initGlobalCopyToClipboardListener} from './features/clipboard.ts';
|
||||||
import {initContextPopups} from './features/contextpopup.ts';
|
import {initContextPopups} from './features/contextpopup.ts';
|
||||||
import {initRepoGraphGit} from './features/repo-graph.ts';
|
import {initRepoGraphGit} from './features/repo-graph.ts';
|
||||||
|
@ -53,7 +52,7 @@ import {initRepoWikiForm} from './features/repo-wiki.ts';
|
||||||
import {initRepository, initBranchSelectorTabs} from './features/repo-legacy.ts';
|
import {initRepository, initBranchSelectorTabs} from './features/repo-legacy.ts';
|
||||||
import {initCopyContent} from './features/copycontent.ts';
|
import {initCopyContent} from './features/copycontent.ts';
|
||||||
import {initCaptcha} from './features/captcha.ts';
|
import {initCaptcha} from './features/captcha.ts';
|
||||||
import {initRepositoryActionView} from './components/RepoActionView.vue';
|
import {initRepositoryActionView} from './features/repo-actions.ts';
|
||||||
import {initGlobalTooltips} from './modules/tippy.ts';
|
import {initGlobalTooltips} from './modules/tippy.ts';
|
||||||
import {initGiteaFomantic} from './modules/fomantic.ts';
|
import {initGiteaFomantic} from './modules/fomantic.ts';
|
||||||
import {initSubmitEventPolyfill, onDomReady} from './utils/dom.ts';
|
import {initSubmitEventPolyfill, onDomReady} from './utils/dom.ts';
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {queryElemChildren} from '../../utils/dom.ts';
|
||||||
|
|
||||||
export function initFomanticDimmer() {
|
export function initFomanticDimmer() {
|
||||||
// stand-in for removed dimmer module
|
// stand-in for removed dimmer module
|
||||||
$.fn.dimmer = function (arg0: string, arg1: any) {
|
$.fn.dimmer = function (this: any, arg0: string, arg1: any) {
|
||||||
if (arg0 === 'add content') {
|
if (arg0 === 'add content') {
|
||||||
const $el = arg1;
|
const $el = arg1;
|
||||||
const existingDimmer = document.querySelector('body > .ui.dimmer');
|
const existingDimmer = document.querySelector('body > .ui.dimmer');
|
||||||
|
|
|
@ -17,7 +17,7 @@ export function initAriaDropdownPatch() {
|
||||||
// the patched `$.fn.dropdown` function, it passes the arguments to Fomantic's `$.fn.dropdown` function, and:
|
// the patched `$.fn.dropdown` function, it passes the arguments to Fomantic's `$.fn.dropdown` function, and:
|
||||||
// * it does the one-time attaching on the first call
|
// * it does the one-time attaching on the first call
|
||||||
// * it delegates the `onLabelCreate` to the patched `onLabelCreate` to add necessary aria attributes
|
// * it delegates the `onLabelCreate` to the patched `onLabelCreate` to add necessary aria attributes
|
||||||
function ariaDropdownFn(...args: Parameters<FomanticInitFunction>) {
|
function ariaDropdownFn(this: any, ...args: Parameters<FomanticInitFunction>) {
|
||||||
const ret = fomanticDropdownFn.apply(this, args);
|
const ret = fomanticDropdownFn.apply(this, args);
|
||||||
|
|
||||||
// if the `$().dropdown()` call is without arguments, or it has non-string (object) argument,
|
// if the `$().dropdown()` call is without arguments, or it has non-string (object) argument,
|
||||||
|
@ -76,18 +76,18 @@ function delegateOne($dropdown: any) {
|
||||||
const oldFocusSearch = dropdownCall('internal', 'focusSearch');
|
const oldFocusSearch = dropdownCall('internal', 'focusSearch');
|
||||||
const oldBlurSearch = dropdownCall('internal', 'blurSearch');
|
const oldBlurSearch = dropdownCall('internal', 'blurSearch');
|
||||||
// * If the "dropdown icon" is clicked, Fomantic calls "focusSearch", so show the menu
|
// * If the "dropdown icon" is clicked, Fomantic calls "focusSearch", so show the menu
|
||||||
dropdownCall('internal', 'focusSearch', function () { dropdownCall('show'); oldFocusSearch.call(this) });
|
dropdownCall('internal', 'focusSearch', function (this: any) { dropdownCall('show'); oldFocusSearch.call(this) });
|
||||||
// * If the "dropdown icon" is clicked again when the menu is visible, Fomantic calls "blurSearch", so hide the menu
|
// * If the "dropdown icon" is clicked again when the menu is visible, Fomantic calls "blurSearch", so hide the menu
|
||||||
dropdownCall('internal', 'blurSearch', function () { oldBlurSearch.call(this); dropdownCall('hide') });
|
dropdownCall('internal', 'blurSearch', function (this: any) { oldBlurSearch.call(this); dropdownCall('hide') });
|
||||||
|
|
||||||
const oldFilterItems = dropdownCall('internal', 'filterItems');
|
const oldFilterItems = dropdownCall('internal', 'filterItems');
|
||||||
dropdownCall('internal', 'filterItems', function (...args: any[]) {
|
dropdownCall('internal', 'filterItems', function (this: any, ...args: any[]) {
|
||||||
oldFilterItems.call(this, ...args);
|
oldFilterItems.call(this, ...args);
|
||||||
processMenuItems($dropdown, dropdownCall);
|
processMenuItems($dropdown, dropdownCall);
|
||||||
});
|
});
|
||||||
|
|
||||||
const oldShow = dropdownCall('internal', 'show');
|
const oldShow = dropdownCall('internal', 'show');
|
||||||
dropdownCall('internal', 'show', function (...args: any[]) {
|
dropdownCall('internal', 'show', function (this: any, ...args: any[]) {
|
||||||
oldShow.call(this, ...args);
|
oldShow.call(this, ...args);
|
||||||
processMenuItems($dropdown, dropdownCall);
|
processMenuItems($dropdown, dropdownCall);
|
||||||
});
|
});
|
||||||
|
@ -110,7 +110,7 @@ function delegateOne($dropdown: any) {
|
||||||
|
|
||||||
// the `onLabelCreate` is used to add necessary aria attributes for dynamically created selection labels
|
// the `onLabelCreate` is used to add necessary aria attributes for dynamically created selection labels
|
||||||
const dropdownOnLabelCreateOld = dropdownCall('setting', 'onLabelCreate');
|
const dropdownOnLabelCreateOld = dropdownCall('setting', 'onLabelCreate');
|
||||||
dropdownCall('setting', 'onLabelCreate', function(value: any, text: string) {
|
dropdownCall('setting', 'onLabelCreate', function(this: any, value: any, text: string) {
|
||||||
const $label = dropdownOnLabelCreateOld.call(this, value, text);
|
const $label = dropdownOnLabelCreateOld.call(this, value, text);
|
||||||
updateSelectionLabel($label[0]);
|
updateSelectionLabel($label[0]);
|
||||||
return $label;
|
return $label;
|
||||||
|
|
|
@ -12,7 +12,7 @@ export function initAriaModalPatch() {
|
||||||
|
|
||||||
// the patched `$.fn.modal` modal function
|
// the patched `$.fn.modal` modal function
|
||||||
// * it does the one-time attaching on the first call
|
// * it does the one-time attaching on the first call
|
||||||
function ariaModalFn(...args: Parameters<FomanticInitFunction>) {
|
function ariaModalFn(this: any, ...args: Parameters<FomanticInitFunction>) {
|
||||||
const ret = fomanticModalFn.apply(this, args);
|
const ret = fomanticModalFn.apply(this, args);
|
||||||
if (args[0] === 'show' || args[0]?.autoShow) {
|
if (args[0] === 'show' || args[0]?.autoShow) {
|
||||||
for (const el of this) {
|
for (const el of this) {
|
||||||
|
|
|
@ -121,7 +121,7 @@ function switchTitleToTooltip(target: Element): void {
|
||||||
* Some browsers like PaleMoon don't support "addEventListener('mouseenter', capture)"
|
* Some browsers like PaleMoon don't support "addEventListener('mouseenter', capture)"
|
||||||
* The tippy by default uses "mouseenter" event to show, so we use "mouseover" event to switch to tippy
|
* The tippy by default uses "mouseenter" event to show, so we use "mouseover" event to switch to tippy
|
||||||
*/
|
*/
|
||||||
function lazyTooltipOnMouseHover(e: Event): void {
|
function lazyTooltipOnMouseHover(this: HTMLElement, e: Event): void {
|
||||||
e.target.removeEventListener('mouseover', lazyTooltipOnMouseHover, true);
|
e.target.removeEventListener('mouseover', lazyTooltipOnMouseHover, true);
|
||||||
attachTooltip(this);
|
attachTooltip(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {h} from 'vue';
|
import {defineComponent, h, type PropType} from 'vue';
|
||||||
import {parseDom, serializeXml} from './utils.ts';
|
import {parseDom, serializeXml} from './utils.ts';
|
||||||
import giteaDoubleChevronLeft from '../../public/assets/img/svg/gitea-double-chevron-left.svg';
|
import giteaDoubleChevronLeft from '../../public/assets/img/svg/gitea-double-chevron-left.svg';
|
||||||
import giteaDoubleChevronRight from '../../public/assets/img/svg/gitea-double-chevron-right.svg';
|
import giteaDoubleChevronRight from '../../public/assets/img/svg/gitea-double-chevron-right.svg';
|
||||||
|
@ -194,10 +194,10 @@ export function svgParseOuterInner(name: SvgName) {
|
||||||
return {svgOuter, svgInnerHtml};
|
return {svgOuter, svgInnerHtml};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SvgIcon = {
|
export const SvgIcon = defineComponent({
|
||||||
name: 'SvgIcon',
|
name: 'SvgIcon',
|
||||||
props: {
|
props: {
|
||||||
name: {type: String, required: true},
|
name: {type: String as PropType<SvgName>, required: true},
|
||||||
size: {type: Number, default: 16},
|
size: {type: Number, default: 16},
|
||||||
className: {type: String, default: ''},
|
className: {type: String, default: ''},
|
||||||
symbolId: {type: String},
|
symbolId: {type: String},
|
||||||
|
@ -215,7 +215,7 @@ export const SvgIcon = {
|
||||||
attrs[`^height`] = this.size;
|
attrs[`^height`] = this.size;
|
||||||
|
|
||||||
// make the <SvgIcon class="foo" class-name="bar"> classes work together
|
// make the <SvgIcon class="foo" class-name="bar"> classes work together
|
||||||
const classes = [];
|
const classes: Array<string> = [];
|
||||||
for (const cls of svgOuter.classList) {
|
for (const cls of svgOuter.classList) {
|
||||||
classes.push(cls);
|
classes.push(cls);
|
||||||
}
|
}
|
||||||
|
@ -234,4 +234,4 @@ export const SvgIcon = {
|
||||||
innerHTML: svgInnerHtml,
|
innerHTML: svgInnerHtml,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
Loading…
Reference in New Issue