Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Take a stab at porting existing components to Vue3 #20044

Merged
merged 10 commits into from
Oct 1, 2022
761 changes: 271 additions & 490 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@claviska/jquery-minicolors": "2.3.6",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-2",
"@primer/octicons": "17.5.0",
"@vue/compiler-sfc": "3.2.37",
"add-asset-webpack-plugin": "2.0.1",
"css-loader": "6.7.1",
"dropzone": "6.0.0-beta.2",
Expand All @@ -34,11 +35,10 @@
"tippy.js": "6.3.7",
"tributejs": "5.1.3",
"uint8-to-base64": "0.2.0",
"vue": "2.6.14",
"vue-bar-graph": "1.3.1",
"vue-calendar-heatmap": "0.8.4",
"vue-loader": "15.9.8",
"vue-template-compiler": "2.6.14",
"vue": "3.2.37",
"vue-bar-graph": "2.0.0",
"vue-loader": "17.0.0",
"vue3-calendar-heatmap": "2.0.0",
"webpack": "5.74.0",
"webpack-cli": "4.10.0",
"workbox-routing": "6.5.4",
Expand Down
4 changes: 2 additions & 2 deletions templates/repo/diff/box.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@
}
})();
</script>
<div id="diff-file-list-container"></div>
<div id="diff-file-list"></div>
<div id="diff-container">
<div id="diff-file-tree-container"></div>
<div id="diff-file-tree"></div>
<div id="diff-file-boxes" class="sixteen wide column">
{{range $i, $file := .Diff.Files}}
{{/*notice: the index of Diff.Files should not be used for element ID, because the index will be restarted from 0 when doing load-more for PRs with a lot of files*/}}
Expand Down
8 changes: 5 additions & 3 deletions templates/user/dashboard/repolist.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
{{end}}
inline-template
v-cloak
>
></repo-search>
</div>

<template id="dashboard-repo-list-template">
<div>
<div v-if="!isOrganization" class="ui two item tabable menu">
<a :class="{item: true, active: tab === 'repos'}" @click="changeTab('repos')">{{.locale.Tr "repository"}}</a>
Expand Down Expand Up @@ -193,5 +196,4 @@
</div>
</div>
</div>
</repo-search>
</div>
</template>
2 changes: 1 addition & 1 deletion web_src/js/components/ActivityHeatmap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</div>
</template>
<script>
wxiaoguang marked this conversation as resolved.
Show resolved Hide resolved
import {CalendarHeatmap} from 'vue-calendar-heatmap';
import {CalendarHeatmap} from 'vue3-calendar-heatmap';
6543 marked this conversation as resolved.
Show resolved Hide resolved

export default {
name: 'ActivityHeatmap',
Expand Down
12 changes: 5 additions & 7 deletions web_src/js/components/ContextPopup.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<div>
<div ref="root">
<div v-if="loading" class="ui active centered inline loader"/>
<div v-if="!loading && issue !== null">
<p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p>
Expand Down Expand Up @@ -109,15 +109,16 @@ export default {
},

mounted() {
this.$root.$on('load-context-popup', (data, callback) => {
this.$refs.root.addEventListener('us-load-context-popup', (e) => {
const data = e.detail;
if (!this.loading && this.issue === null) {
this.load(data, callback);
this.load(data);
}
});
},

methods: {
load(data, callback) {
load(data) {
this.loading = true;
this.i18nErrorMessage = null;
$.get(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`).done((issue) => {
Expand All @@ -130,9 +131,6 @@ export default {
}
}).always(() => {
this.loading = false;
if (callback) {
this.$nextTick(callback);
}
});
}
}
Expand Down
40 changes: 21 additions & 19 deletions web_src/js/components/DashboardRepoList.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Vue from 'vue';
import {createApp, nextTick} from 'vue';
import $ from 'jquery';
import {initVueSvg, vueDelimiters} from './VueComponentLoader.js';
import {initTooltip} from '../modules/tippy.js';

const {appSubUrl, assetUrlPrefix, pageData} = window.config;

function initVueComponents() {
Vue.component('repo-search', {
function initVueComponents(app) {
app.component('repo-search', {
6543 marked this conversation as resolved.
Show resolved Hide resolved
delimiters: vueDelimiters,
props: {
searchLimit: {
Expand Down Expand Up @@ -138,13 +138,14 @@ function initVueComponents() {
},

mounted() {
const el = document.getElementById('dashboard-repo-list');
this.changeReposFilter(this.reposFilter);
for (const el of this.$el.querySelectorAll('.tooltip')) {
initTooltip(el);
for (const elTooltip of el.querySelectorAll('.tooltip')) {
initTooltip(elTooltip);
}
$(this.$el).find('.dropdown').dropdown();
$(el).find('.dropdown').dropdown();
this.setCheckboxes();
Vue.nextTick(() => {
nextTick(() => {
this.$refs.search.focus();
});
},
Expand Down Expand Up @@ -192,7 +193,7 @@ function initVueComponents() {
this.reposFilter = filter;
this.repos = [];
this.page = 1;
Vue.set(this.counts, `${filter}:${this.archivedFilter}:${this.privateFilter}`, 0);
this.counts[`${filter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
this.searchRepos();
},

Expand Down Expand Up @@ -261,7 +262,7 @@ function initVueComponents() {
this.page = 1;
this.repos = [];
this.setCheckboxes();
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
this.searchRepos();
},

Expand All @@ -283,7 +284,7 @@ function initVueComponents() {
this.page = 1;
this.repos = [];
this.setCheckboxes();
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
this.searchRepos();
},

Expand All @@ -297,7 +298,7 @@ function initVueComponents() {
this.page = 1;
}
this.repos = [];
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
this.searchRepos();
},

Expand Down Expand Up @@ -331,7 +332,7 @@ function initVueComponents() {
if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') {
this.reposTotalCount = count;
}
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, count);
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = count;
this.finalPage = Math.ceil(count / this.searchLimit);
this.updateHistory();
this.isLoading = false;
Expand All @@ -352,27 +353,28 @@ function initVueComponents() {
}
return 'octicon-repo';
}
}
},

template: document.getElementById('dashboard-repo-list-template'),
});
}


export function initDashboardRepoList() {
const el = document.getElementById('dashboard-repo-list');
const dashboardRepoListData = pageData.dashboardRepoList || null;
if (!el || !dashboardRepoListData) return;

initVueSvg();
initVueComponents();
new Vue({
el,
const app = createApp({
delimiters: vueDelimiters,
data: () => {
data() {
return {
searchLimit: dashboardRepoListData.searchLimit || 0,
subUrl: appSubUrl,
uid: dashboardRepoListData.uid || 0,
};
},
});
initVueSvg(app);
initVueComponents(app);
app.mount(el);
}
4 changes: 2 additions & 2 deletions web_src/js/components/DiffFileList.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<ol class="diff-detail-box diff-stats m-0" id="diff-files" v-if="fileListIsVisible">
<ol class="diff-detail-box diff-stats m-0" ref="root" v-if="fileListIsVisible">
<li v-for="file in files" :key="file.NameHash">
<div class="bold df ac pull-right">
<span v-if="file.IsBin" class="ml-1 mr-3">{{ binaryFileMessage }}</span>
Expand Down Expand Up @@ -37,7 +37,7 @@ export default {
fileListIsVisible(newValue) {
if (newValue === true) {
this.$nextTick(() => {
for (const el of this.$el.querySelectorAll('.tooltip')) {
for (const el of this.$refs.root.querySelectorAll('.tooltip')) {
initTooltip(el);
}
});
Expand Down
8 changes: 5 additions & 3 deletions web_src/js/components/DiffFileTree.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
<template>
<div
v-show="fileTreeIsVisible"
id="diff-file-tree"
v-if="fileTreeIsVisible"
class="mr-3 mt-3 diff-detail-box"
>
<!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
<div class="ui list" v-if="fileTreeIsVisible">
<div class="ui list">
<DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item" />
</div>
<div v-if="isIncomplete" id="diff-too-many-files-stats" class="pt-2">
Expand Down Expand Up @@ -117,6 +116,9 @@ export default {
const [toShow, toHide] = document.querySelectorAll('.diff-toggle-file-tree-button .icon');
toShow.classList.toggle('hide', visible); // hide the toShow icon if the tree is visible
toHide.classList.toggle('hide', !visible); // similarly

const diffTree = document.getElementById('diff-file-tree');
diffTree.classList.toggle('hide', !visible);
},
loadMoreData() {
this.isLoadingNewData = true;
Expand Down
43 changes: 24 additions & 19 deletions web_src/js/components/RepoBranchTagDropdown.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Vue from 'vue';
import {createApp, nextTick} from 'vue';
import $ from 'jquery';
import {vueDelimiters} from './VueComponentLoader.js';

Expand Down Expand Up @@ -37,10 +37,14 @@ export function initRepoBranchTagDropdown(selector) {
});
});
$data.remove();
new Vue({
el: this,

// eslint-disable-next-line unicorn/no-this-assignment
const elRoot = this;
const view = createApp({
delimiters: vueDelimiters,
data,
data() {
return data;
},
computed: {
filteredItems() {
const items = this.items.filter((item) => {
Expand Down Expand Up @@ -73,10 +77,10 @@ export function initRepoBranchTagDropdown(selector) {
},

beforeMount() {
this.noResults = this.$el.getAttribute('data-no-results');
this.canCreateBranch = this.$el.getAttribute('data-can-create-branch') === 'true';
this.branchForm = this.$el.getAttribute('data-branch-form');
switch (this.$el.getAttribute('data-view-type')) {
this.noResults = elRoot.getAttribute('data-no-results');
this.canCreateBranch = elRoot.getAttribute('data-can-create-branch') === 'true';
this.branchForm = elRoot.getAttribute('data-branch-form');
switch (elRoot.getAttribute('data-view-type')) {
case 'tree':
this.isViewTree = true;
break;
Expand All @@ -87,19 +91,19 @@ export function initRepoBranchTagDropdown(selector) {
this.isViewBranch = true;
break;
}
this.refName = this.$el.getAttribute('data-ref-name');
this.branchURLPrefix = this.$el.getAttribute('data-branch-url-prefix');
this.branchURLSuffix = this.$el.getAttribute('data-branch-url-suffix');
this.tagURLPrefix = this.$el.getAttribute('data-tag-url-prefix');
this.tagURLSuffix = this.$el.getAttribute('data-tag-url-suffix');
this.setAction = this.$el.getAttribute('data-set-action') === 'true';
this.submitForm = this.$el.getAttribute('data-submit-form') === 'true';
this.refName = elRoot.getAttribute('data-ref-name');
this.branchURLPrefix = elRoot.getAttribute('data-branch-url-prefix');
this.branchURLSuffix = elRoot.getAttribute('data-branch-url-suffix');
this.tagURLPrefix = elRoot.getAttribute('data-tag-url-prefix');
this.tagURLSuffix = elRoot.getAttribute('data-tag-url-suffix');
this.setAction = elRoot.getAttribute('data-set-action') === 'true';
this.submitForm = elRoot.getAttribute('data-submit-form') === 'true';


document.body.addEventListener('click', (event) => {
if (this.$el.contains(event.target)) return;
if (elRoot.contains(event.target)) return;
if (this.menuVisible) {
Vue.set(this, 'menuVisible', false);
this.menuVisible = false;
}
});
},
Expand Down Expand Up @@ -135,15 +139,15 @@ export function initRepoBranchTagDropdown(selector) {
if (this.submitForm) {
$(`#${this.branchForm}`).trigger('submit');
}
Vue.set(this, 'menuVisible', false);
this.menuVisible = false;
}
},
createNewBranch() {
if (!this.showCreateNewBranch) return;
$(this.$refs.newBranchForm).trigger('submit');
},
focusSearchField() {
Vue.nextTick(() => {
nextTick(() => {
this.$refs.searchField.focus();
});
},
Expand Down Expand Up @@ -213,5 +217,6 @@ export function initRepoBranchTagDropdown(selector) {
}
}
});
view.mount(this);
});
}
20 changes: 10 additions & 10 deletions web_src/js/components/VueComponentLoader.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Vue from 'vue';
import {createApp} from 'vue';
import {svgs} from '../svg.js';

export const vueDelimiters = ['${', '}'];
Expand All @@ -8,13 +8,14 @@ export function initVueEnv() {
if (vueEnvInited) return;
vueEnvInited = true;

const isProd = window.config.runModeIsProd;
Vue.config.productionTip = false;
Vue.config.devtools = !isProd;
// As far as I could tell, this is no longer possible.
// But there seem not to be a guide what to do instead.
// const isProd = window.config.runModeIsProd;
// Vue.config.devtools = !isProd;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this option was moved to compile-time config, https://github.com/vuejs/core/tree/main/packages/vue#bundler-build-feature-flags, but it might just be that it's no longer necessary to get rid of devtools in prod build as the docs sound like it's disabled by default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, compile-time config won't be evaluated at runtime, though. That is, I can't go via window.config anymore.

The value is injected in

runModeIsProd: {{.RunModeIsProd}},

which in turn is defined in

"RunModeIsProd": setting.IsProd,

which in turn is derived from

RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod")
IsProd = strings.EqualFold(RunMode, "prod")

… so … is there a way I can somehow read this from Node.js?

}

let vueSvgInited = false;
export function initVueSvg() {
export function initVueSvg(app) {
6543 marked this conversation as resolved.
Show resolved Hide resolved
if (vueSvgInited) return;
vueSvgInited = true;

Expand All @@ -24,7 +25,7 @@ export function initVueSvg() {
.replace(/height="[0-9]+"/, 'v-bind:height="size"')
.replace(/width="[0-9]+"/, 'v-bind:width="size"');

Vue.component(name, {
app.component(name, {
props: {
size: {
type: String,
Expand All @@ -42,8 +43,7 @@ export function initVueApp(el, opts = {}) {
}
if (!el) return null;

return new Vue(Object.assign({
el,
delimiters: vueDelimiters,
}, opts));
return createApp(
Object.assign({delimiters: vueDelimiters}, opts)
).mount(el);
}
Loading