Compare commits

...

3 Commits

Author SHA1 Message Date
Lunny Xiao
2b0b56319e
Improve testing for pgsql empty repository (#22223) 2022-12-23 12:34:51 -06:00
silverwind
2cf0cf0de1
JS refactors (#22227)
- Replace all default exports with named exports, except for Vue SFCs
- Remove names from Vue SFCs, they are automatically inferred from the
filename
- Misc whitespace-related tweaks
2022-12-24 00:03:11 +08:00
Jason Song
71ca3067bc
Check primary keys for all tables and drop ForeignReference (#21721)
Some dbs require that all tables have primary keys, see
- #16802
- #21086

We can add a test to keep it from being broken again.

Edit:

~Added missing primary key for `ForeignReference`~ Dropped the
`ForeignReference` table to satisfy the check, so it closes #21086.

More context can be found in comments.

Signed-off-by: Andrew Thornton <art27@cantab.net>
Co-authored-by: zeripath <art27@cantab.net>
2022-12-23 19:35:43 +08:00
47 changed files with 106 additions and 293 deletions

View File

@ -12,6 +12,8 @@ import (
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/setting"
_ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys
"github.com/stretchr/testify/assert"
)
@ -51,3 +53,34 @@ func TestDeleteOrphanedObjects(t *testing.T) {
assert.NoError(t, err)
assert.EqualValues(t, countBefore, countAfter)
}
func TestPrimaryKeys(t *testing.T) {
// Some dbs require that all tables have primary keys, see
// https://github.com/go-gitea/gitea/issues/21086
// https://github.com/go-gitea/gitea/issues/16802
// To avoid creating tables without primary key again, this test will check them.
// Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called.
beans, err := db.NamesToBean()
if err != nil {
t.Fatal(err)
}
whitelist := map[string]string{
"the_table_name_to_skip_checking": "Write a note here to explain why",
}
for _, bean := range beans {
table, err := db.TableInfo(bean)
if err != nil {
t.Fatal(err)
}
if why, ok := whitelist[table.Name]; ok {
t.Logf("ignore %q because %q", table.Name, why)
continue
}
if len(table.PrimaryKeys) == 0 {
t.Errorf("table %q has no primary key", table.Name)
}
}
}

View File

@ -1 +0,0 @@
[] # empty

View File

@ -1,52 +0,0 @@
// Copyright 2022 Gitea. All rights reserved.
// SPDX-License-Identifier: MIT
package foreignreference
import (
"fmt"
"code.gitea.io/gitea/modules/util"
)
// ErrLocalIndexNotExist represents a "LocalIndexNotExist" kind of error.
type ErrLocalIndexNotExist struct {
RepoID int64
ForeignIndex int64
Type string
}
// ErrLocalIndexNotExist checks if an error is a ErrLocalIndexNotExist.
func IsErrLocalIndexNotExist(err error) bool {
_, ok := err.(ErrLocalIndexNotExist)
return ok
}
func (err ErrLocalIndexNotExist) Error() string {
return fmt.Sprintf("repository %d has no LocalIndex for ForeignIndex %d of type %s", err.RepoID, err.ForeignIndex, err.Type)
}
func (err ErrLocalIndexNotExist) Unwrap() error {
return util.ErrNotExist
}
// ErrForeignIndexNotExist represents a "ForeignIndexNotExist" kind of error.
type ErrForeignIndexNotExist struct {
RepoID int64
LocalIndex int64
Type string
}
// ErrForeignIndexNotExist checks if an error is a ErrForeignIndexNotExist.
func IsErrForeignIndexNotExist(err error) bool {
_, ok := err.(ErrForeignIndexNotExist)
return ok
}
func (err ErrForeignIndexNotExist) Error() string {
return fmt.Sprintf("repository %d has no ForeignIndex for LocalIndex %d of type %s", err.RepoID, err.LocalIndex, err.Type)
}
func (err ErrForeignIndexNotExist) Unwrap() error {
return util.ErrNotExist
}

View File

@ -1,31 +0,0 @@
// Copyright 2022 Gitea. All rights reserved.
// SPDX-License-Identifier: MIT
package foreignreference
import (
"code.gitea.io/gitea/models/db"
)
// Type* are valid values for the Type field of ForeignReference
const (
TypeIssue = "issue"
TypePullRequest = "pull_request"
TypeComment = "comment"
TypeReview = "review"
TypeReviewComment = "review_comment"
TypeRelease = "release"
)
// ForeignReference represents external references
type ForeignReference struct {
// RepoID is the first column in all indices. now we only need 2 indices: (repo, local) and (repo, foreign, type)
RepoID int64 `xorm:"UNIQUE(repo_foreign_type) INDEX(repo_local)" `
LocalIndex int64 `xorm:"INDEX(repo_local)"` // the resource key inside Gitea, it can be IssueIndex, or some model ID.
ForeignIndex string `xorm:"INDEX UNIQUE(repo_foreign_type)"`
Type string `xorm:"VARCHAR(16) INDEX UNIQUE(repo_foreign_type)"`
}
func init() {
db.RegisterModel(new(ForeignReference))
}

View File

@ -9,11 +9,9 @@ import (
"fmt"
"regexp"
"sort"
"strconv"
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference"
"code.gitea.io/gitea/models/organization"
"code.gitea.io/gitea/models/perm"
access_model "code.gitea.io/gitea/models/perm/access"
@ -136,12 +134,11 @@ type Issue struct {
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
ClosedUnix timeutil.TimeStamp `xorm:"INDEX"`
Attachments []*repo_model.Attachment `xorm:"-"`
Comments []*Comment `xorm:"-"`
Reactions ReactionList `xorm:"-"`
TotalTrackedTime int64 `xorm:"-"`
Assignees []*user_model.User `xorm:"-"`
ForeignReference *foreignreference.ForeignReference `xorm:"-"`
Attachments []*repo_model.Attachment `xorm:"-"`
Comments []*Comment `xorm:"-"`
Reactions ReactionList `xorm:"-"`
TotalTrackedTime int64 `xorm:"-"`
Assignees []*user_model.User `xorm:"-"`
// IsLocked limits commenting abilities to users on an issue
// with write access
@ -321,29 +318,6 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) {
return nil
}
func (issue *Issue) loadForeignReference(ctx context.Context) (err error) {
if issue.ForeignReference != nil {
return nil
}
reference := &foreignreference.ForeignReference{
RepoID: issue.RepoID,
LocalIndex: issue.Index,
Type: foreignreference.TypeIssue,
}
has, err := db.GetEngine(ctx).Get(reference)
if err != nil {
return err
} else if !has {
return foreignreference.ErrForeignIndexNotExist{
RepoID: issue.RepoID,
LocalIndex: issue.Index,
Type: foreignreference.TypeIssue,
}
}
issue.ForeignReference = reference
return nil
}
// LoadMilestone load milestone of this issue.
func (issue *Issue) LoadMilestone(ctx context.Context) (err error) {
if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 {
@ -406,10 +380,6 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) {
}
}
if err = issue.loadForeignReference(ctx); err != nil && !foreignreference.IsErrForeignIndexNotExist(err) {
return err
}
return issue.loadReactions(ctx)
}
@ -1097,26 +1067,6 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) {
return issue, nil
}
// GetIssueByForeignIndex returns raw issue by foreign ID
func GetIssueByForeignIndex(ctx context.Context, repoID, foreignIndex int64) (*Issue, error) {
reference := &foreignreference.ForeignReference{
RepoID: repoID,
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
Type: foreignreference.TypeIssue,
}
has, err := db.GetEngine(ctx).Get(reference)
if err != nil {
return nil, err
} else if !has {
return nil, foreignreference.ErrLocalIndexNotExist{
RepoID: repoID,
ForeignIndex: foreignIndex,
Type: foreignreference.TypeIssue,
}
}
return GetIssueByIndex(repoID, reference.LocalIndex)
}
// GetIssueWithAttrsByIndex returns issue by index in a repository.
func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) {
issue, err := GetIssueByIndex(repoID, index)

View File

@ -7,13 +7,11 @@ import (
"context"
"fmt"
"sort"
"strconv"
"sync"
"testing"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference"
issues_model "code.gitea.io/gitea/models/issues"
"code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo"
@ -501,38 +499,6 @@ func TestCorrectIssueStats(t *testing.T) {
assert.EqualValues(t, issueStats.OpenCount, issueAmount)
}
func TestIssueForeignReference(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4})
assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive
// it is fine for an issue to not have a foreign reference
err := issue.LoadAttributes(db.DefaultContext)
assert.NoError(t, err)
assert.Nil(t, issue.ForeignReference)
var foreignIndex int64 = 12345
_, err = issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
assert.True(t, foreignreference.IsErrLocalIndexNotExist(err))
err = db.Insert(db.DefaultContext, &foreignreference.ForeignReference{
LocalIndex: issue.Index,
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
RepoID: issue.RepoID,
Type: foreignreference.TypeIssue,
})
assert.NoError(t, err)
err = issue.LoadAttributes(db.DefaultContext)
assert.NoError(t, err)
assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10))
found, err := issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex)
assert.NoError(t, err)
assert.EqualValues(t, found.Index, issue.Index)
}
func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
miles := issues_model.MilestoneList{

View File

@ -83,13 +83,6 @@ func insertIssue(ctx context.Context, issue *issues_model.Issue) error {
}
}
if issue.ForeignReference != nil {
issue.ForeignReference.LocalIndex = issue.Index
if _, err := sess.Insert(issue.ForeignReference); err != nil {
return err
}
}
return nil
}

View File

@ -4,11 +4,9 @@
package models
import (
"strconv"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
@ -48,7 +46,6 @@ func assertCreateIssues(t *testing.T, isPull bool) {
UserID: owner.ID,
}
foreignIndex := int64(12345)
title := "issuetitle1"
is := &issues_model.Issue{
RepoID: repo.ID,
@ -62,20 +59,11 @@ func assertCreateIssues(t *testing.T, isPull bool) {
IsClosed: true,
Labels: []*issues_model.Label{label},
Reactions: []*issues_model.Reaction{reaction},
ForeignReference: &foreignreference.ForeignReference{
ForeignIndex: strconv.FormatInt(foreignIndex, 10),
RepoID: repo.ID,
Type: foreignreference.TypeIssue,
},
}
err := InsertIssues(is)
assert.NoError(t, err)
i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title})
assert.Nil(t, i.ForeignReference)
err = i.LoadAttributes(db.DefaultContext)
assert.NoError(t, err)
assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex)
unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID})
}

View File

@ -444,6 +444,8 @@ var migrations = []Migration{
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
// v236 -> v237
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
// v237 -> v238
NewMigration("Drop ForeignReference table", v1_19.DropForeignReferenceTable),
}
// GetCurrentDBVersion returns the current db version

View File

@ -0,0 +1,15 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_19 //nolint
import (
"xorm.io/xorm"
)
func DropForeignReferenceTable(x *xorm.Engine) error {
// Drop the table introduced in `v211`, it's considered badly designed and doesn't look like to be used.
// See: https://github.com/go-gitea/gitea/issues/21086#issuecomment-1318217453
type ForeignReference struct{}
return x.DropTables(new(ForeignReference))
}

View File

@ -17,7 +17,6 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/foreignreference"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
@ -403,16 +402,6 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error {
Labels: labels,
CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()),
UpdatedUnix: timeutil.TimeStamp(issue.Updated.Unix()),
ForeignReference: &foreignreference.ForeignReference{
LocalIndex: issue.GetLocalIndex(),
ForeignIndex: strconv.FormatInt(issue.GetForeignIndex(), 10),
RepoID: g.repo.ID,
Type: foreignreference.TypeIssue,
},
}
if is.ForeignReference.ForeignIndex == "0" {
is.ForeignReference.ForeignIndex = strconv.FormatInt(is.Index, 10)
}
if err := g.remapUser(issue, &is); err != nil {

View File

@ -11,6 +11,8 @@ import (
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
)
func TestEmptyRepo(t *testing.T) {
@ -21,7 +23,8 @@ func TestEmptyRepo(t *testing.T) {
"commit/1ae57b34ccf7e18373",
"graph",
}
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}, unittest.Cond("is_empty = ?", true))
emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 5})
assert.True(t, emptyRepo.IsEmpty)
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID})
for _, subpath := range subpaths {
req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subpath)

View File

@ -18,7 +18,6 @@
import {CalendarHeatmap} from 'vue3-calendar-heatmap';
export default {
name: 'ActivityHeatmap',
components: {CalendarHeatmap},
props: {
values: {

View File

@ -46,19 +46,13 @@ const luminance = (colorString) => {
const luminanceThreshold = 0.179;
export default {
name: 'ContextPopup',
components: {
SvgIcon,
},
components: {SvgIcon},
data: () => ({
loading: false,
issue: null,
i18nErrorOccurred: i18n.error_occurred,
i18nErrorMessage: null,
}),
computed: {
createdAt() {
return new Date(this.issue.created_at).toLocaleDateString(undefined, {year: 'numeric', month: 'short', day: 'numeric'});
@ -107,7 +101,6 @@ export default {
});
}
},
mounted() {
this.$refs.root.addEventListener('us-load-context-popup', (e) => {
const data = e.detail;
@ -116,7 +109,6 @@ export default {
}
});
},
methods: {
load(data) {
this.loading = true;

View File

@ -27,12 +27,9 @@ import {doLoadMoreFiles} from '../features/repo-diff.js';
const {pageData} = window.config;
export default {
name: 'DiffFileList',
data: () => {
return pageData.diffFileInfo;
},
watch: {
fileListIsVisible(newValue) {
if (newValue === true) {
@ -44,15 +41,12 @@ export default {
}
}
},
mounted() {
document.getElementById('show-file-list-btn').addEventListener('click', this.toggleFileList);
},
unmounted() {
document.getElementById('show-file-list-btn').removeEventListener('click', this.toggleFileList);
},
methods: {
toggleFileList() {
this.fileListIsVisible = !this.fileListIsVisible;

View File

@ -21,15 +21,12 @@ const {pageData} = window.config;
const LOCAL_STORAGE_KEY = 'diff_file_tree_visible';
export default {
name: 'DiffFileTree',
components: {DiffFileTreeItem},
data: () => {
const fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) === 'true';
pageData.diffFileInfo.fileTreeIsVisible = fileTreeIsVisible;
return pageData.diffFileInfo;
},
computed: {
fileTree() {
const result = [];
@ -94,7 +91,6 @@ export default {
return result;
}
},
mounted() {
// ensure correct buttons when we are mounted to the dom
this.adjustToggleButton(this.fileTreeIsVisible);
@ -125,7 +121,7 @@ export default {
doLoadMoreFiles(this.link, this.diffEnd, () => {
this.isLoadingNewData = false;
});
}
},
},
};
</script>

View File

@ -43,11 +43,7 @@
import {SvgIcon} from '../svg.js';
export default {
name: 'DiffFileTreeItem',
components: {
SvgIcon,
},
components: {SvgIcon},
props: {
item: {
type: Object,
@ -59,7 +55,6 @@ export default {
default: true
}
},
data: () => ({
collapsed: false,
}),

View File

@ -111,11 +111,7 @@ import {SvgIcon} from '../svg.js';
const {csrfToken, pageData} = window.config;
export default {
name: 'PullRequestMergeForm',
components: {
SvgIcon,
},
components: {SvgIcon},
data: () => ({
csrfToken,
mergeForm: pageData.pullRequestMergeForm,
@ -137,20 +133,17 @@ export default {
showMergeStyleMenu: false,
showActionForm: false,
}),
computed: {
mergeButtonStyleClass() {
if (this.mergeForm.allOverridableChecksOk) return 'green';
return this.autoMergeWhenSucceed ? 'blue' : 'red';
}
},
watch: {
mergeStyle(val) {
this.mergeStyleDetail = this.mergeForm.mergeStyles.find((e) => e.name === val);
}
},
created() {
this.mergeStyleAllowedCount = this.mergeForm.mergeStyles.reduce((v, msd) => v + (msd.allowed ? 1 : 0), 0);
@ -158,15 +151,12 @@ export default {
if (!mergeStyle) mergeStyle = this.mergeForm.mergeStyles.find((e) => e.allowed)?.name;
this.switchMergeStyle(mergeStyle, !this.mergeForm.canMergeNow);
},
mounted() {
document.addEventListener('mouseup', this.hideMergeStyleMenu);
},
unmounted() {
document.removeEventListener('mouseup', this.hideMergeStyleMenu);
},
methods: {
hideMergeStyleMenu() {
this.showMergeStyleMenu = false;

View File

@ -44,7 +44,7 @@ function fallbackCopyToClipboard(text) {
// For all DOM elements with [data-clipboard-target] or [data-clipboard-text],
// this copy-to-clipboard will work for them
export default function initGlobalCopyToClipboardListener() {
export function initGlobalCopyToClipboardListener() {
document.addEventListener('click', (e) => {
let target = e.target;
// in case <button data-clipboard-text><svg></button>, so we just search

View File

@ -1,4 +1,4 @@
export default async function createColorPicker($els) {
export async function createColorPicker($els) {
if (!$els || !$els.length) return;
await Promise.all([

View File

@ -1,7 +1,7 @@
import $ from 'jquery';
import 'jquery.are-you-sure';
import {mqBinarySearch} from '../utils.js';
import createDropzone from './dropzone.js';
import {createDropzone} from './dropzone.js';
import {initCompColorPicker} from './comp/ColorPicker.js';
import {showGlobalErrorMessage} from '../bootstrap.js';
import {attachDropdownAria} from './aria.js';

View File

@ -1,5 +1,5 @@
import $ from 'jquery';
import createColorPicker from '../colorpicker.js';
import {createColorPicker} from '../colorpicker.js';
export function initCompColorPicker() {
createColorPicker($('.color-picker'));

View File

@ -1,5 +1,5 @@
import $ from 'jquery';
import attachTribute from '../tribute.js';
import {attachTribute} from '../tribute.js';
import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js';
/**

View File

@ -2,7 +2,6 @@ import $ from 'jquery';
import {htmlEscape} from 'escape-goat';
const {appSubUrl} = window.config;
const looksLikeEmailAddressCheck = /^\S+@\S+$/;
export function initCompSearchUserBox() {

View File

@ -1,4 +1,5 @@
import $ from 'jquery';
const {csrfToken} = window.config;
export function initCompWebHookEditor() {

View File

@ -4,7 +4,7 @@ import ContextPopup from '../components/ContextPopup.vue';
import {parseIssueHref} from '../utils.js';
import {createTippy} from '../modules/tippy.js';
export default function initContextPopups() {
export function initContextPopups() {
const refIssues = $('.ref-issue');
if (!refIssues.length) return;

View File

@ -1,6 +1,7 @@
import {copyToClipboard} from './clipboard.js';
import {showTemporaryTooltip} from '../modules/tippy.js';
import {convertImage} from '../utils.js';
const {i18n} = window.config;
async function doCopy(content, btn) {

View File

@ -1,4 +1,4 @@
export default async function createDropzone(el, opts) {
export async function createDropzone(el, opts) {
const [{Dropzone}] = await Promise.all([
import(/* webpackChunkName: "dropzone" */'dropzone'),
import(/* webpackChunkName: "dropzone" */'dropzone/dist/dropzone.css'),

View File

@ -1,7 +1,6 @@
import emojis from '../../../assets/emoji.json';
const {assetUrlPrefix} = window.config;
const {customEmojis} = window.config;
const {assetUrlPrefix, customEmojis} = window.config;
const tempMap = {...customEmojis};
for (const {emoji, aliases} of emojis) {

View File

@ -1,6 +1,5 @@
import {svg} from '../svg.js';
// Hides the file if newFold is true, and shows it otherwise. The actual hiding is performed using CSS.
//
// The fold arrow is the icon displayed on the upper left of the file box, especially intended for components having the 'fold-file' class.

View File

@ -1,7 +1,6 @@
import {prettyNumber} from '../utils.js';
const {lang} = document.documentElement;
const dateFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'long', day: 'numeric'});
const shortDateFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'short', day: 'numeric'});
const dateTimeFormatter = new Intl.DateTimeFormat(lang, {year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric'});

View File

@ -1,7 +1,8 @@
import {createApp} from 'vue';
import ActivityHeatmap from '../components/ActivityHeatmap.vue';
import {translateMonth, translateDay} from '../utils.js';
export default function initHeatmap() {
export function initHeatmap() {
const el = document.getElementById('user-heatmap');
if (!el) return;

View File

@ -34,7 +34,7 @@ function getDefaultSvgBoundsIfUndefined(svgXml, src) {
return null;
}
export default function initImageDiff() {
export function initImageDiff() {
function createContext(image1, image2) {
const size1 = {
width: image1 && image1.width || 0,

View File

@ -2,7 +2,7 @@ import {createApp} from 'vue';
import DiffFileTree from '../components/DiffFileTree.vue';
import DiffFileList from '../components/DiffFileList.vue';
export default function initDiffFileTree() {
export function initDiffFileTree() {
const el = document.getElementById('diff-file-tree');
if (!el) return;

View File

@ -1,6 +1,6 @@
import $ from 'jquery';
import {svg} from '../svg.js';
const {csrf} = window.config;
const threshold = 50;

View File

@ -1,6 +1,6 @@
import $ from 'jquery';
export default function initRepoGraphGit() {
export function initRepoGraphGit() {
const graphContainer = document.getElementById('git-graph-container');
if (!graphContainer) return;

View File

@ -1,7 +1,7 @@
import {createApp} from 'vue';
import PullRequestMergeForm from '../components/PullRequestMergeForm.vue';
export default function initPullRequestMergeForm() {
export function initRepoPullRequestMergeForm() {
const el = document.getElementById('pull-request-merge-form');
if (!el) return;

View File

@ -1,6 +1,6 @@
import $ from 'jquery';
import {htmlEscape} from 'escape-goat';
import attachTribute from './tribute.js';
import {attachTribute} from './tribute.js';
import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js';
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';

View File

@ -3,33 +3,28 @@ import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js';
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
import {
initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel,
initRepoIssueCommentDelete,
initRepoIssueComments, initRepoIssueDependencyDelete,
initRepoIssueReferenceIssue, initRepoIssueStatusButton,
initRepoIssueTitleEdit,
initRepoIssueWipToggle, initRepoPullRequestUpdate,
updateIssuesMeta,
initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel, initRepoIssueCommentDelete,
initRepoIssueComments, initRepoIssueDependencyDelete, initRepoIssueReferenceIssue,
initRepoIssueStatusButton, initRepoIssueTitleEdit, initRepoIssueWipToggle,
initRepoPullRequestUpdate, updateIssuesMeta,
} from './repo-issue.js';
import {initUnicodeEscapeButton} from './repo-unicode-escape.js';
import {svg} from '../svg.js';
import {htmlEscape} from 'escape-goat';
import {initRepoBranchTagDropdown} from '../components/RepoBranchTagDropdown.js';
import {
initRepoCloneLink,
initRepoCommonBranchOrTagDropdown,
initRepoCommonFilterSearchDropdown,
initRepoCloneLink, initRepoCommonBranchOrTagDropdown, initRepoCommonFilterSearchDropdown,
initRepoCommonLanguageStats,
} from './repo-common.js';
import {initCitationFileCopyContent} from './citation.js';
import {initCompLabelEdit} from './comp/LabelEdit.js';
import {initRepoDiffConversationNav} from './repo-diff.js';
import attachTribute from './tribute.js';
import createDropzone from './dropzone.js';
import {attachTribute} from './tribute.js';
import {createDropzone} from './dropzone.js';
import {initCommentContent, initMarkupContent} from '../markup/content.js';
import {initCompReactionSelector} from './comp/ReactionSelector.js';
import {initRepoSettingBranches} from './repo-settings.js';
import initRepoPullRequestMergeForm from './repo-issue-pr-form.js';
import {initRepoPullRequestMergeForm} from './repo-issue-pr-form.js';
const {csrfToken} = window.config;

View File

@ -10,7 +10,7 @@ const $lfsSettings = $('#lfs_settings');
const $lfsEndpoint = $('#lfs_endpoint');
const $items = $('#migrate_items').find('input[type=checkbox]');
export default function initRepoMigration() {
export function initRepoMigration() {
checkAuth();
setLFSSettingsVisibility();

View File

@ -84,7 +84,7 @@ async function initRepoProjectSortable() {
}
}
export default function initRepoProject() {
export function initRepoProject() {
if (!$('.repository.projects').length) {
return;
}

View File

@ -1,5 +1,5 @@
import $ from 'jquery';
import attachTribute from './tribute.js';
import {attachTribute} from './tribute.js';
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
import {createCommentEasyMDE} from './comp/EasyMDE.js';

View File

@ -35,7 +35,7 @@ async function checkCacheValidity() {
}
}
export default async function initServiceWorker() {
export async function initServiceWorker() {
if (!('serviceWorker' in navigator)) return;
if (useServiceWorker) {

View File

@ -1,4 +1,4 @@
export default function initTableSort() {
export function initTableSort() {
for (const header of document.querySelectorAll('th[data-sortt-asc]') || []) {
const sorttAsc = header.getAttribute('data-sortt-asc');
const sorttDesc = header.getAttribute('data-sortt-desc');

View File

@ -49,7 +49,7 @@ function makeCollections({mentions, emoji}) {
return collections;
}
export default async function attachTribute(elementOrNodeList, {mentions, emoji} = {}) {
export async function attachTribute(elementOrNodeList, {mentions, emoji} = {}) {
if (!window.config.requireTribute || !elementOrNodeList) return;
const nodes = Array.from('length' in elementOrNodeList ? elementOrNodeList : [elementOrNodeList]);
if (!nodes.length) return;

View File

@ -6,16 +6,16 @@ import {initVueEnv} from './components/VueComponentLoader.js';
import {initRepoActivityTopAuthorsChart} from './components/RepoActivityTopAuthors.vue';
import {initDashboardRepoList} from './components/DashboardRepoList.js';
import attachTribute from './features/tribute.js';
import initGlobalCopyToClipboardListener from './features/clipboard.js';
import initContextPopups from './features/contextpopup.js';
import initRepoGraphGit from './features/repo-graph.js';
import initHeatmap from './features/heatmap.js';
import initImageDiff from './features/imagediff.js';
import initRepoMigration from './features/repo-migration.js';
import initRepoProject from './features/repo-projects.js';
import initServiceWorker from './features/serviceworker.js';
import initTableSort from './features/tablesort.js';
import {attachTribute} from './features/tribute.js';
import {initGlobalCopyToClipboardListener} from './features/clipboard.js';
import {initContextPopups} from './features/contextpopup.js';
import {initRepoGraphGit} from './features/repo-graph.js';
import {initHeatmap} from './features/heatmap.js';
import {initImageDiff} from './features/imagediff.js';
import {initRepoMigration} from './features/repo-migration.js';
import {initRepoProject} from './features/repo-projects.js';
import {initServiceWorker} from './features/serviceworker.js';
import {initTableSort} from './features/tablesort.js';
import {initAdminUserListSearchForm} from './features/admin/users.js';
import {initAdminConfigs} from './features/admin/config.js';
import {initMarkupAnchors} from './markup/anchors.js';
@ -24,7 +24,7 @@ import {initRepoIssueContentHistory} from './features/repo-issue-content.js';
import {initStopwatch} from './features/stopwatch.js';
import {initFindFileInRepo} from './features/repo-findfile.js';
import {initCommentContent, initMarkupContent} from './markup/content.js';
import initDiffFileTree from './features/repo-diff-filetree.js';
import {initDiffFileTree} from './features/repo-diff-filetree.js';
import {initUserAuthLinkAccountView, initUserAuthOauth2} from './features/user-auth.js';
import {

View File

@ -26,7 +26,6 @@ import octiconSidebarExpand from '../../public/img/svg/octicon-sidebar-expand.sv
import octiconTriangleDown from '../../public/img/svg/octicon-triangle-down.svg';
import octiconX from '../../public/img/svg/octicon-x.svg';
export const svgs = {
'octicon-chevron-down': octiconChevronDown,
'octicon-chevron-right': octiconChevronRight,
@ -57,7 +56,6 @@ export const svgs = {
'octicon-x': octiconX,
};
const parser = new DOMParser();
const serializer = new XMLSerializer();