mirror of
https://github.com/go-gitea/gitea
synced 2026-02-03 12:20:40 +00:00
Remove and forbid @ts-expect-error (#36513)
Removes `@ts-expect-error` in the code base and forbids it. --------- Signed-off-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: silverwind <115237+silverwind@users.noreply.github.com> Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
+4
-5
@@ -15,6 +15,7 @@ import vue from 'eslint-plugin-vue';
|
|||||||
import vueScopedCss from 'eslint-plugin-vue-scoped-css';
|
import vueScopedCss from 'eslint-plugin-vue-scoped-css';
|
||||||
import wc from 'eslint-plugin-wc';
|
import wc from 'eslint-plugin-wc';
|
||||||
import {defineConfig, globalIgnores} from 'eslint/config';
|
import {defineConfig, globalIgnores} from 'eslint/config';
|
||||||
|
import type {ESLint} from 'eslint';
|
||||||
|
|
||||||
const jsExts = ['js', 'mjs', 'cjs'] as const;
|
const jsExts = ['js', 'mjs', 'cjs'] as const;
|
||||||
const tsExts = ['ts', 'mts', 'cts'] as const;
|
const tsExts = ['ts', 'mts', 'cts'] as const;
|
||||||
@@ -62,8 +63,7 @@ export default defineConfig([
|
|||||||
'@stylistic': stylistic,
|
'@stylistic': stylistic,
|
||||||
'@typescript-eslint': typescriptPlugin.plugin,
|
'@typescript-eslint': typescriptPlugin.plugin,
|
||||||
'array-func': arrayFunc,
|
'array-func': arrayFunc,
|
||||||
// @ts-expect-error -- https://github.com/un-ts/eslint-plugin-import-x/issues/203
|
'import-x': importPlugin as unknown as ESLint.Plugin, // https://github.com/un-ts/eslint-plugin-import-x/issues/203
|
||||||
'import-x': importPlugin,
|
|
||||||
regexp,
|
regexp,
|
||||||
sonarjs,
|
sonarjs,
|
||||||
unicorn,
|
unicorn,
|
||||||
@@ -156,7 +156,7 @@ export default defineConfig([
|
|||||||
'@typescript-eslint/adjacent-overload-signatures': [0],
|
'@typescript-eslint/adjacent-overload-signatures': [0],
|
||||||
'@typescript-eslint/array-type': [0],
|
'@typescript-eslint/array-type': [0],
|
||||||
'@typescript-eslint/await-thenable': [2],
|
'@typescript-eslint/await-thenable': [2],
|
||||||
'@typescript-eslint/ban-ts-comment': [2, {'ts-expect-error': false, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}],
|
'@typescript-eslint/ban-ts-comment': [2, {'ts-expect-error': true, 'ts-ignore': true, 'ts-nocheck': false, 'ts-check': false}],
|
||||||
'@typescript-eslint/ban-tslint-comment': [0],
|
'@typescript-eslint/ban-tslint-comment': [0],
|
||||||
'@typescript-eslint/class-literal-property-style': [0],
|
'@typescript-eslint/class-literal-property-style': [0],
|
||||||
'@typescript-eslint/class-methods-use-this': [0],
|
'@typescript-eslint/class-methods-use-this': [0],
|
||||||
@@ -924,8 +924,7 @@ export default defineConfig([
|
|||||||
},
|
},
|
||||||
extends: [
|
extends: [
|
||||||
vue.configs['flat/recommended'],
|
vue.configs['flat/recommended'],
|
||||||
// @ts-expect-error
|
vueScopedCss.configs['flat/recommended'] as any,
|
||||||
vueScopedCss.configs['flat/recommended'],
|
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
'vue/attributes-order': [0],
|
'vue/attributes-order': [0],
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@
|
|||||||
"target": "es2020",
|
"target": "es2020",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"lib": ["dom", "dom.iterable", "dom.asynciterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "dom.asynciterable", "esnext", "webworker"],
|
||||||
"allowImportingTsExtensions": true,
|
"allowImportingTsExtensions": true,
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
|
|||||||
Vendored
+87
@@ -2,18 +2,105 @@ declare module '@techknowlogick/license-checker-webpack-plugin' {
|
|||||||
const plugin: any;
|
const plugin: any;
|
||||||
export = plugin;
|
export = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'eslint-plugin-no-use-extend-native' {
|
declare module 'eslint-plugin-no-use-extend-native' {
|
||||||
import type {Eslint} from 'eslint';
|
import type {Eslint} from 'eslint';
|
||||||
const plugin: Eslint.Plugin;
|
const plugin: Eslint.Plugin;
|
||||||
export = plugin;
|
export = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'eslint-plugin-array-func' {
|
declare module 'eslint-plugin-array-func' {
|
||||||
import type {Eslint} from 'eslint';
|
import type {Eslint} from 'eslint';
|
||||||
const plugin: Eslint.Plugin;
|
const plugin: Eslint.Plugin;
|
||||||
export = plugin;
|
export = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'eslint-plugin-github' {
|
declare module 'eslint-plugin-github' {
|
||||||
import type {Eslint} from 'eslint';
|
import type {Eslint} from 'eslint';
|
||||||
const plugin: Eslint.Plugin;
|
const plugin: Eslint.Plugin;
|
||||||
export = plugin;
|
export = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare module '*.svg' {
|
||||||
|
const value: string;
|
||||||
|
export default value;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.css' {
|
||||||
|
const value: string;
|
||||||
|
export default value;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '*.vue' {
|
||||||
|
import type {DefineComponent} from 'vue';
|
||||||
|
const component: DefineComponent<unknown, unknown, any>;
|
||||||
|
export default component;
|
||||||
|
// Here we declare all exports from vue files so `tsc` or `tsgo` can work for
|
||||||
|
// non-vue files. To lint .vue files, `vue-tsc` must be used.
|
||||||
|
export function initDashboardRepoList(): void;
|
||||||
|
export function initRepositoryActionView(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'htmx.org/dist/htmx.esm.js' {
|
||||||
|
const value = await import('htmx.org');
|
||||||
|
export default value;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'swagger-ui-dist/swagger-ui-es-bundle.js' {
|
||||||
|
const value = await import('swagger-ui-dist');
|
||||||
|
export default value.SwaggerUIBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'asciinema-player' {
|
||||||
|
interface AsciinemaPlayer {
|
||||||
|
create(src: string, element: HTMLElement, options?: Record<string, unknown>): void;
|
||||||
|
}
|
||||||
|
const exports: AsciinemaPlayer;
|
||||||
|
export = exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@citation-js/core' {
|
||||||
|
export class Cite {
|
||||||
|
constructor(data: string);
|
||||||
|
format(format: string, options?: Record<string, any>): string;
|
||||||
|
}
|
||||||
|
export const plugins: {
|
||||||
|
config: {
|
||||||
|
get(name: string): any;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@citation-js/plugin-software-formats' {}
|
||||||
|
declare module '@citation-js/plugin-bibtex' {}
|
||||||
|
declare module '@citation-js/plugin-csl' {}
|
||||||
|
|
||||||
|
declare module 'vue-bar-graph' {
|
||||||
|
import type {DefineComponent} from 'vue';
|
||||||
|
|
||||||
|
interface BarGraphPoint {
|
||||||
|
value: number;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const VueBarGraph: DefineComponent<{
|
||||||
|
points?: Array<BarGraphPoint>;
|
||||||
|
barColor?: string;
|
||||||
|
textColor?: string;
|
||||||
|
textAltColor?: string;
|
||||||
|
height?: number;
|
||||||
|
labelHeight?: number;
|
||||||
|
}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module '@mcaptcha/vanilla-glue' {
|
||||||
|
export let INPUT_NAME: string;
|
||||||
|
export default class Widget {
|
||||||
|
constructor(options: {
|
||||||
|
siteKey: {
|
||||||
|
instanceUrl: URL;
|
||||||
|
key: string;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,13 +80,12 @@ function initGlobalErrorHandler() {
|
|||||||
// we added an event handler for window error at the very beginning of <script> of page head the
|
// we added an event handler for window error at the very beginning of <script> of page head the
|
||||||
// handler calls `_globalHandlerErrors.push` (array method) to record all errors occur before
|
// handler calls `_globalHandlerErrors.push` (array method) to record all errors occur before
|
||||||
// this init then in this init, we can collect all error events and show them.
|
// this init then in this init, we can collect all error events and show them.
|
||||||
for (const e of window._globalHandlerErrors || []) {
|
for (const e of (window._globalHandlerErrors as Iterable<ErrorEvent & PromiseRejectionEvent>) || []) {
|
||||||
processWindowErrorEvent(e);
|
processWindowErrorEvent(e);
|
||||||
}
|
}
|
||||||
// then, change _globalHandlerErrors to an object with push method, to process further error
|
// then, change _globalHandlerErrors to an object with push method, to process further error
|
||||||
// events directly
|
// events directly
|
||||||
// @ts-expect-error -- this should be refactored to not use a fake array
|
window._globalHandlerErrors = {_inited: true, push: (e: ErrorEvent & PromiseRejectionEvent) => processWindowErrorEvent(e)} as any;
|
||||||
window._globalHandlerErrors = {_inited: true, push: (e: ErrorEvent & PromiseRejectionEvent) => processWindowErrorEvent(e)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initGlobalErrorHandler();
|
initGlobalErrorHandler();
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import {localUserSettings} from '../modules/user-settings.ts';
|
|||||||
// see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts"
|
// see "models/actions/status.go", if it needs to be used somewhere else, move it to a shared file like "types/actions.ts"
|
||||||
type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
|
type RunStatus = 'unknown' | 'waiting' | 'running' | 'success' | 'failure' | 'cancelled' | 'skipped' | 'blocked';
|
||||||
|
|
||||||
|
type StepContainerElement = HTMLElement & {_stepLogsActiveContainer?: HTMLElement}
|
||||||
|
|
||||||
type LogLine = {
|
type LogLine = {
|
||||||
index: number;
|
index: number;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
@@ -221,19 +223,18 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// get the job step logs container ('.job-step-logs')
|
// get the job step logs container ('.job-step-logs')
|
||||||
getJobStepLogsContainer(stepIndex: number): HTMLElement {
|
getJobStepLogsContainer(stepIndex: number): StepContainerElement {
|
||||||
return (this.$refs.logs as any)[stepIndex];
|
return (this.$refs.logs as any)[stepIndex];
|
||||||
},
|
},
|
||||||
|
|
||||||
// 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): StepContainerElement {
|
||||||
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
|
||||||
beginLogGroup(stepIndex: number, startTime: number, line: LogLine, cmd: LogLineCommand) {
|
beginLogGroup(stepIndex: number, startTime: number, line: LogLine, cmd: LogLineCommand) {
|
||||||
const el = (this.$refs.logs as any)[stepIndex];
|
const el = (this.$refs.logs as any)[stepIndex] as StepContainerElement;
|
||||||
const elJobLogGroupSummary = createElementFromAttrs('summary', {class: 'job-log-group-summary'},
|
const elJobLogGroupSummary = createElementFromAttrs('summary', {class: 'job-log-group-summary'},
|
||||||
this.createLogLine(stepIndex, startTime, {
|
this.createLogLine(stepIndex, startTime, {
|
||||||
index: line.index,
|
index: line.index,
|
||||||
@@ -395,7 +396,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// auto-scroll to the last log line of the last step
|
// auto-scroll to the last log line of the last step
|
||||||
let autoScrollJobStepElement: HTMLElement | undefined;
|
let autoScrollJobStepElement: StepContainerElement | undefined;
|
||||||
for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) {
|
for (let stepIndex = 0; stepIndex < this.currentJob.steps.length; stepIndex++) {
|
||||||
if (!autoScrollStepIndexes.get(stepIndex)) continue;
|
if (!autoScrollStepIndexes.get(stepIndex)) continue;
|
||||||
autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex);
|
autoScrollJobStepElement = this.getJobStepLogsContainer(stepIndex);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
// @ts-expect-error - module exports no types
|
|
||||||
import {VueBarGraph} from 'vue-bar-graph';
|
import {VueBarGraph} from 'vue-bar-graph';
|
||||||
import {computed, onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue';
|
import {computed, onMounted, shallowRef, useTemplateRef, type ShallowRef} from 'vue';
|
||||||
|
|
||||||
|
|||||||
@@ -155,9 +155,8 @@ export default defineComponent({
|
|||||||
return -1;
|
return -1;
|
||||||
},
|
},
|
||||||
getActiveItem() {
|
getActiveItem() {
|
||||||
const el = this.$refs[`listItem${this.activeItemIndex}`];
|
const el = this.$refs[`listItem${this.activeItemIndex}`] as Array<HTMLDivElement>;
|
||||||
// @ts-expect-error - el is unknown type
|
return el?.length ? el[0] : null;
|
||||||
return (el && el.length) ? el[0] : null;
|
|
||||||
},
|
},
|
||||||
keydown(e: KeyboardEvent) {
|
keydown(e: KeyboardEvent) {
|
||||||
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
|
||||||
@@ -174,7 +173,7 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.activeItemIndex = nextIndex;
|
this.activeItemIndex = nextIndex;
|
||||||
this.getActiveItem().scrollIntoView({block: 'nearest'});
|
this.getActiveItem()!.scrollIntoView({block: 'nearest'});
|
||||||
} else if (e.key === 'Enter') {
|
} else if (e.key === 'Enter') {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.getActiveItem()?.click();
|
this.getActiveItem()?.click();
|
||||||
|
|||||||
@@ -41,6 +41,15 @@ const customEventListener: Plugin = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LineOptions = ChartOptions<'line'> & {
|
||||||
|
plugins?: {
|
||||||
|
customEventListener?: {
|
||||||
|
chartType: string;
|
||||||
|
instance: unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
Chart.defaults.color = chartJsColors.text;
|
Chart.defaults.color = chartJsColors.text;
|
||||||
Chart.defaults.borderColor = chartJsColors.border;
|
Chart.defaults.borderColor = chartJsColors.border;
|
||||||
|
|
||||||
@@ -251,7 +260,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getOptions(type: string): ChartOptions<'line'> {
|
getOptions(type: string): LineOptions {
|
||||||
return {
|
return {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
@@ -264,7 +273,6 @@ export default defineComponent({
|
|||||||
position: 'top',
|
position: 'top',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
},
|
},
|
||||||
// @ts-expect-error: bug in chart.js types
|
|
||||||
customEventListener: {
|
customEventListener: {
|
||||||
chartType: type,
|
chartType: type,
|
||||||
instance: this,
|
instance: this,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
TimeScale,
|
TimeScale,
|
||||||
type ChartOptions,
|
type ChartOptions,
|
||||||
type ChartData,
|
type ChartData,
|
||||||
|
type ChartDataset,
|
||||||
} from 'chart.js';
|
} from 'chart.js';
|
||||||
import {GET} from '../modules/fetch.ts';
|
import {GET} from '../modules/fetch.ts';
|
||||||
import {Bar} from 'vue-chartjs';
|
import {Bar} from 'vue-chartjs';
|
||||||
@@ -83,13 +84,12 @@ function toGraphData(data: DayData[]): ChartData<'bar'> {
|
|||||||
return {
|
return {
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
// @ts-expect-error -- bar chart expects one-dimensional data, but apparently x/y still works
|
|
||||||
data: data.map((i) => ({x: i.week, y: i.commits})),
|
data: data.map((i) => ({x: i.week, y: i.commits})),
|
||||||
label: 'Commits',
|
label: 'Commits',
|
||||||
backgroundColor: chartJsColors['commits'],
|
backgroundColor: chartJsColors['commits'],
|
||||||
borderWidth: 0,
|
borderWidth: 0,
|
||||||
tension: 0.3,
|
tension: 0.3,
|
||||||
},
|
} as unknown as ChartDataset<'bar'>,
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ export async function initCaptcha() {
|
|||||||
// * the INPUT_NAME is a "const", it should not be changed.
|
// * the INPUT_NAME is a "const", it should not be changed.
|
||||||
// * the "mCaptcha.default" is actually the "Widget".
|
// * the "mCaptcha.default" is actually the "Widget".
|
||||||
|
|
||||||
// @ts-expect-error TS2540: Cannot assign to 'INPUT_NAME' because it is a read-only property.
|
|
||||||
mCaptcha.INPUT_NAME = 'm-captcha-response';
|
mCaptcha.INPUT_NAME = 'm-captcha-response';
|
||||||
const instanceURL = captchaEl.getAttribute('data-instance-url')!;
|
const instanceURL = captchaEl.getAttribute('data-instance-url')!;
|
||||||
|
|
||||||
|
|||||||
@@ -6,13 +6,9 @@ const {pageData} = window.config;
|
|||||||
|
|
||||||
async function initInputCitationValue(citationCopyApa: HTMLButtonElement, citationCopyBibtex: HTMLButtonElement) {
|
async function initInputCitationValue(citationCopyApa: HTMLButtonElement, citationCopyBibtex: HTMLButtonElement) {
|
||||||
const [{Cite, plugins}] = await Promise.all([
|
const [{Cite, plugins}] = await Promise.all([
|
||||||
// @ts-expect-error: module exports no types
|
|
||||||
import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'),
|
import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'),
|
||||||
// @ts-expect-error: module exports no types
|
|
||||||
import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'),
|
import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'),
|
||||||
// @ts-expect-error: module exports no types
|
|
||||||
import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'),
|
import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'),
|
||||||
// @ts-expect-error: module exports no types
|
|
||||||
import(/* webpackChunkName: "citation-js-csl" */'@citation-js/plugin-csl'),
|
import(/* webpackChunkName: "citation-js-csl" */'@citation-js/plugin-csl'),
|
||||||
]);
|
]);
|
||||||
const {citationFileContent} = pageData;
|
const {citationFileContent} = pageData;
|
||||||
|
|||||||
@@ -72,10 +72,9 @@ class Source {
|
|||||||
const sourcesByUrl = new Map<string, Source | null>();
|
const sourcesByUrl = new Map<string, Source | null>();
|
||||||
const sourcesByPort = new Map<MessagePort, Source | null>();
|
const sourcesByPort = new Map<MessagePort, Source | null>();
|
||||||
|
|
||||||
// @ts-expect-error: typescript bug?
|
(self as unknown as SharedWorkerGlobalScope).addEventListener('connect', (e: MessageEvent) => {
|
||||||
self.addEventListener('connect', (e: MessageEvent) => {
|
|
||||||
for (const port of e.ports) {
|
for (const port of e.ports) {
|
||||||
port.addEventListener('message', (event) => {
|
port.addEventListener('message', (event: MessageEvent) => {
|
||||||
if (!self.EventSource) {
|
if (!self.EventSource) {
|
||||||
// some browsers (like PaleMoon, Firefox<53) don't support EventSource in SharedWorkerGlobalScope.
|
// some browsers (like PaleMoon, Firefox<53) don't support EventSource in SharedWorkerGlobalScope.
|
||||||
// this event handler needs EventSource when doing "new Source(url)", so just post a message back to the caller,
|
// this event handler needs EventSource when doing "new Source(url)", so just post a message back to the caller,
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ function initRepoDiffConversationForm() {
|
|||||||
const idx = newConversationHolder.getAttribute('data-idx');
|
const idx = newConversationHolder.getAttribute('data-idx');
|
||||||
|
|
||||||
form.closest('.conversation-holder')!.replaceWith(newConversationHolder);
|
form.closest('.conversation-holder')!.replaceWith(newConversationHolder);
|
||||||
// @ts-expect-error -- prevent further usage of the form because it should have been replaced
|
(form as any) = null; // prevent further usage of the form because it should have been replaced
|
||||||
form = null;
|
|
||||||
|
|
||||||
if (trLineType) {
|
if (trLineType) {
|
||||||
// if there is a line-type for the "tr", it means the form is on the diff page
|
// if there is a line-type for the "tr", it means the form is on the diff page
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ async function pinMoveEnd(e: SortableEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function initIssuePinSort() {
|
async function initIssuePinSort() {
|
||||||
const pinDiv = document.querySelector('#issue-pins');
|
const pinDiv = document.querySelector<HTMLElement>('#issue-pins');
|
||||||
|
|
||||||
if (pinDiv === null) return;
|
if (pinDiv === null) return;
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ async function moveIssue({item, from, to, oldIndex}: SortableEvent): Promise<voi
|
|||||||
|
|
||||||
async function initRepoProjectSortable(): Promise<void> {
|
async function initRepoProjectSortable(): Promise<void> {
|
||||||
// the HTML layout is: #project-board.board > .project-column .cards > .issue-card
|
// the HTML layout is: #project-board.board > .project-column .cards > .issue-card
|
||||||
const mainBoard = document.querySelector('#project-board')!;
|
const mainBoard = document.querySelector<HTMLElement>('#project-board')!;
|
||||||
let boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column');
|
let boardColumns = mainBoard.querySelectorAll<HTMLElement>('.project-column');
|
||||||
createSortable(mainBoard, {
|
createSortable(mainBoard, {
|
||||||
group: 'project-column',
|
group: 'project-column',
|
||||||
@@ -67,7 +67,7 @@ async function initRepoProjectSortable(): Promise<void> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const boardColumn of boardColumns) {
|
for (const boardColumn of boardColumns) {
|
||||||
const boardCardList = boardColumn.querySelector('.cards')!;
|
const boardCardList = boardColumn.querySelector<HTMLElement>('.cards')!;
|
||||||
createSortable(boardCardList, {
|
createSortable(boardCardList, {
|
||||||
group: 'shared',
|
group: 'shared',
|
||||||
onAdd: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises
|
onAdd: moveIssue, // eslint-disable-line @typescript-eslint/no-misused-promises
|
||||||
|
|||||||
@@ -56,12 +56,11 @@ describe('Repository Branch Settings', () => {
|
|||||||
vi.mocked(POST).mockResolvedValue({ok: true} as Response);
|
vi.mocked(POST).mockResolvedValue({ok: true} as Response);
|
||||||
|
|
||||||
// Mock createSortable to capture and execute the onEnd callback
|
// Mock createSortable to capture and execute the onEnd callback
|
||||||
vi.mocked(createSortable).mockImplementation(async (_el: Element, options: SortableOptions | undefined) => {
|
vi.mocked(createSortable).mockImplementation(async (_el: HTMLElement, options: SortableOptions | undefined) => {
|
||||||
if (options?.onEnd) {
|
if (options?.onEnd) {
|
||||||
options.onEnd(new Event('SortableEvent') as SortableEvent);
|
options.onEnd(new Event('SortableEvent') as SortableEvent);
|
||||||
}
|
}
|
||||||
// @ts-expect-error: mock is incomplete
|
return {destroy: vi.fn()} as unknown as Sortable;
|
||||||
return {destroy: vi.fn()} as Sortable;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
initRepoSettingsBranchesDrag();
|
initRepoSettingsBranchesDrag();
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {showErrorToast} from '../modules/toast.ts';
|
|||||||
import {queryElemChildren} from '../utils/dom.ts';
|
import {queryElemChildren} from '../utils/dom.ts';
|
||||||
|
|
||||||
export function initRepoSettingsBranchesDrag() {
|
export function initRepoSettingsBranchesDrag() {
|
||||||
const protectedBranchesList = document.querySelector('#protected-branches-list');
|
const protectedBranchesList = document.querySelector<HTMLElement>('#protected-branches-list');
|
||||||
if (!protectedBranchesList) return;
|
if (!protectedBranchesList) return;
|
||||||
|
|
||||||
createSortable(protectedBranchesList, {
|
createSortable(protectedBranchesList, {
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
import {emojiKeys, emojiHTML, emojiString} from './emoji.ts';
|
import {emojiKeys, emojiHTML, emojiString} from './emoji.ts';
|
||||||
import {html, htmlRaw} from '../utils/html.ts';
|
import {html, htmlRaw} from '../utils/html.ts';
|
||||||
|
import type {TributeCollection} from 'tributejs';
|
||||||
type TributeItem = Record<string, any>;
|
|
||||||
|
|
||||||
export async function attachTribute(element: HTMLElement) {
|
export async function attachTribute(element: HTMLElement) {
|
||||||
const {default: Tribute} = await import(/* webpackChunkName: "tribute" */'tributejs');
|
const {default: Tribute} = await import(/* webpackChunkName: "tribute" */'tributejs');
|
||||||
|
|
||||||
const collections = [
|
const emojiCollection: TributeCollection<string> = { // emojis
|
||||||
{ // emojis
|
|
||||||
trigger: ':',
|
trigger: ':',
|
||||||
requireLeadingSpace: true,
|
requireLeadingSpace: true,
|
||||||
values: (query: string, cb: (matches: Array<string>) => void) => {
|
values: (query: string, cb: (matches: Array<string>) => void) => {
|
||||||
@@ -20,18 +18,20 @@ export async function attachTribute(element: HTMLElement) {
|
|||||||
}
|
}
|
||||||
cb(matches);
|
cb(matches);
|
||||||
},
|
},
|
||||||
lookup: (item: TributeItem) => item,
|
lookup: (item) => item,
|
||||||
selectTemplate: (item: TributeItem) => {
|
selectTemplate: (item) => {
|
||||||
if (item === undefined) return null;
|
if (item === undefined) return '';
|
||||||
return emojiString(item.original);
|
return emojiString(item.original) ?? '';
|
||||||
},
|
},
|
||||||
menuItemTemplate: (item: TributeItem) => {
|
menuItemTemplate: (item) => {
|
||||||
return html`<div class="tribute-item">${htmlRaw(emojiHTML(item.original))}<span>${item.original}</span></div>`;
|
return html`<div class="tribute-item">${htmlRaw(emojiHTML(item.original))}<span>${item.original}</span></div>`;
|
||||||
},
|
},
|
||||||
}, { // mentions
|
};
|
||||||
|
|
||||||
|
const mentionCollection: TributeCollection<Record<string, any>> = {
|
||||||
values: window.config.mentionValues,
|
values: window.config.mentionValues,
|
||||||
requireLeadingSpace: true,
|
requireLeadingSpace: true,
|
||||||
menuItemTemplate: (item: TributeItem) => {
|
menuItemTemplate: (item) => {
|
||||||
const fullNameHtml = item.original.fullname && item.original.fullname !== '' ? html`<span class="fullname">${item.original.fullname}</span>` : '';
|
const fullNameHtml = item.original.fullname && item.original.fullname !== '' ? html`<span class="fullname">${item.original.fullname}</span>` : '';
|
||||||
return html`
|
return html`
|
||||||
<div class="tribute-item">
|
<div class="tribute-item">
|
||||||
@@ -41,11 +41,12 @@ export async function attachTribute(element: HTMLElement) {
|
|||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
},
|
},
|
||||||
},
|
};
|
||||||
];
|
|
||||||
|
|
||||||
// @ts-expect-error TS2351: This expression is not constructable (strange, why)
|
const tribute = new Tribute({
|
||||||
const tribute = new Tribute({collection: collections, noMatchTemplate: ''});
|
collection: [emojiCollection as TributeCollection<any>, mentionCollection],
|
||||||
|
noMatchTemplate: () => '',
|
||||||
|
});
|
||||||
tribute.attach(element);
|
tribute.attach(element);
|
||||||
return tribute;
|
return tribute;
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-30
@@ -1,33 +1,3 @@
|
|||||||
declare module '*.svg' {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.css' {
|
|
||||||
const value: string;
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module '*.vue' {
|
|
||||||
import type {DefineComponent} from 'vue';
|
|
||||||
const component: DefineComponent<unknown, unknown, any>;
|
|
||||||
export default component;
|
|
||||||
// Here we declare all exports from vue files so `tsc` or `tsgo` can work for
|
|
||||||
// non-vue files. To lint .vue files, `vue-tsc` must be used.
|
|
||||||
export function initDashboardRepoList(): void;
|
|
||||||
export function initRepositoryActionView(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'htmx.org/dist/htmx.esm.js' {
|
|
||||||
const value = await import('htmx.org');
|
|
||||||
export default value;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module 'swagger-ui-dist/swagger-ui-es-bundle.js' {
|
|
||||||
const value = await import('swagger-ui-dist');
|
|
||||||
export default value.SwaggerUIBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface JQuery {
|
interface JQuery {
|
||||||
areYouSure: any, // jquery.are-you-sure
|
areYouSure: any, // jquery.are-you-sure
|
||||||
fomanticExt: any; // fomantic extension
|
fomanticExt: any; // fomantic extension
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import {queryElems} from '../utils/dom.ts';
|
|||||||
export async function initMarkupRenderAsciicast(elMarkup: HTMLElement): Promise<void> {
|
export async function initMarkupRenderAsciicast(elMarkup: HTMLElement): Promise<void> {
|
||||||
queryElems(elMarkup, '.asciinema-player-container', async (el) => {
|
queryElems(elMarkup, '.asciinema-player-container', async (el) => {
|
||||||
const [player] = await Promise.all([
|
const [player] = await Promise.all([
|
||||||
// @ts-expect-error: module exports no types
|
|
||||||
import(/* webpackChunkName: "asciinema-player" */'asciinema-player'),
|
import(/* webpackChunkName: "asciinema-player" */'asciinema-player'),
|
||||||
import(/* webpackChunkName: "asciinema-player" */'asciinema-player/dist/bundle/asciinema-player.css'),
|
import(/* webpackChunkName: "asciinema-player" */'asciinema-player/dist/bundle/asciinema-player.css'),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
player.create(el.getAttribute('data-asciinema-player-src'), el, {
|
player.create(el.getAttribute('data-asciinema-player-src')!, el, {
|
||||||
// poster (a preview frame) to display until the playback is started.
|
// poster (a preview frame) to display until the playback is started.
|
||||||
// Set it to 1 hour (also means the end if the video is shorter) to make the preview frame show more.
|
// Set it to 1 hour (also means the end if the video is shorter) to make the preview frame show more.
|
||||||
poster: 'npt:1:0:0',
|
poster: 'npt:1:0:0',
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import type {SortableOptions, SortableEvent} from 'sortablejs';
|
import type {SortableOptions, SortableEvent} from 'sortablejs';
|
||||||
import type SortableType from 'sortablejs';
|
import type SortableType from 'sortablejs';
|
||||||
|
|
||||||
export async function createSortable(el: Element, opts: {handle?: string} & SortableOptions = {}): Promise<SortableType> {
|
export async function createSortable(el: HTMLElement, opts: {handle?: string} & SortableOptions = {}): Promise<SortableType> {
|
||||||
// @ts-expect-error: wrong type derived by typescript
|
// type reassigned because typescript derives the wrong type from this import
|
||||||
const {Sortable} = await import(/* webpackChunkName: "sortablejs" */'sortablejs');
|
const {Sortable} = (await import(/* webpackChunkName: "sortablejs" */'sortablejs') as unknown as {Sortable: typeof SortableType});
|
||||||
|
|
||||||
return new Sortable(el, {
|
return new Sortable(el, {
|
||||||
animation: 150,
|
animation: 150,
|
||||||
|
|||||||
@@ -4,17 +4,16 @@ try {
|
|||||||
new Intl.NumberFormat('en', {style: 'unit', unit: 'minute'}).format(1);
|
new Intl.NumberFormat('en', {style: 'unit', unit: 'minute'}).format(1);
|
||||||
} catch {
|
} catch {
|
||||||
const intlNumberFormat = Intl.NumberFormat;
|
const intlNumberFormat = Intl.NumberFormat;
|
||||||
// @ts-expect-error - polyfill is incomplete
|
|
||||||
Intl.NumberFormat = function(locales: string | string[], options: Intl.NumberFormatOptions) {
|
Intl.NumberFormat = function(locales: string | string[], options: Intl.NumberFormatOptions) {
|
||||||
if (options.style === 'unit') {
|
if (options.style === 'unit') {
|
||||||
return {
|
return {
|
||||||
format(value: number | bigint | string) {
|
format(value: number | bigint | string) {
|
||||||
return ` ${value} ${options.unit}`;
|
return ` ${value} ${options.unit}`;
|
||||||
},
|
},
|
||||||
};
|
} as Intl.NumberFormat;
|
||||||
}
|
}
|
||||||
return intlNumberFormat(locales, options);
|
return intlNumberFormat(locales, options);
|
||||||
};
|
} as unknown as typeof Intl.NumberFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function weakRefClass() {
|
export function weakRefClass() {
|
||||||
|
|||||||
Reference in New Issue
Block a user