Skip to content

Commit

Permalink
[#1936] Migrate app.vue to TypeScript (#1938)
Browse files Browse the repository at this point in the history
Currently, despite the addition of TypeScript support, the frontend is
still largely written in JavaScript. This results in a lack of type
safety and many complex objects being passed around as unknown types,
which may in turn lead to errors.

Let's migrate the root component, app.vue, to TypeScript. As this is the
entry point of the app, converting this file to TypeScript will enable
the conversion of other Vue components.
  • Loading branch information
vvidday committed Mar 21, 2023
1 parent 7b709cb commit 32d49ad
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 43 deletions.
84 changes: 45 additions & 39 deletions frontend/src/app.vue
Expand Up @@ -75,34 +75,48 @@
input(type="file", accept=".zip", v-on:change="updateReportZip")
</template>

<script>
<script lang='ts'>
import JSZip from 'jszip';
import LoadingOverlay from 'vue-loading-overlay';
import { mapState } from 'vuex';
import { defineComponent } from 'vue';
import cResizer from './components/c-resizer.vue';
import cZoom from './views/c-zoom.vue';
import cSummary from './views/c-summary.vue';
import cAuthorship from './views/c-authorship.vue';
import { Repo } from './types/types';
import { ErrorMessage } from './types/zod/summary-type';
import { ZoomInfo, AuthorshipInfo } from './types/vuex.d';
const loadingResourcesMessage = 'Loading resources...';
const app = {
const app = defineComponent({
name: 'app',
components: {
LoadingOverlay,
cResizer,
cZoom,
cSummary,
cAuthorship,
},
data() {
return {
repos: {},
users: [],
repos: {} as { [key: string]: Repo },
users: [] as Repo[],
userUpdated: false,
loadingOverlayOpacity: 1,
tabType: 'empty',
creationDate: '',
reportGenerationTime: '',
errorMessages: {},
errorMessages: {} as { [key: string]: ErrorMessage },
};
},
computed: {
...mapState(['loadingOverlayCount', 'loadingOverlayMessage', 'isTabActive']),
},
watch: {
'$store.state.tabZoomInfo': function () {
if (this.$store.state.tabZoomInfo.isRefreshing) {
Expand All @@ -114,12 +128,23 @@ const app = {
this.activateTab('authorship');
},
},
created() {
try {
window.decodeHash();
} catch (error) {
this.userUpdated = false;
}
this.updateReportDir();
},
methods: {
// model functions //
updateReportZip(evt) {
updateReportZip(evt: Event) {
this.users = [];
JSZip.loadAsync(evt.target.files[0])
const target = evt.target as HTMLInputElement;
if (target.files === null) {
return;
}
JSZip.loadAsync(target.files[0])
.then((zip) => {
window.REPORT_ZIP = zip;
}, () => {
Expand All @@ -141,15 +166,16 @@ const app = {
this.userUpdated = false;
await this.$store.dispatch('incrementLoadingOverlayCountForceReload', 1);
try {
const summary = await window.api.loadSummary();
if (summary === null) {
return;
}
const {
creationDate,
reportGenerationTime,
errorMessages,
names,
} = await window.api.loadSummary();
if (names === null) {
return;
}
} = summary;
this.creationDate = creationDate;
this.reportGenerationTime = reportGenerationTime;
this.errorMessages = errorMessages;
Expand All @@ -168,7 +194,7 @@ const app = {
}
},
getUsers() {
const full = [];
const full: Repo[] = [];
Object.keys(this.repos).forEach((repo) => {
if (this.repos[repo].users) {
full.push(this.repos[repo]);
Expand All @@ -178,9 +204,9 @@ const app = {
},
// handle opening of sidebar //
activateTab(tabName) {
activateTab(tabName: string) {
if (this.$refs.tabWrapper) {
this.$refs.tabWrapper.scrollTop = 0;
(this.$refs.tabWrapper as HTMLElement).scrollTop = 0;
}
this.tabType = tabName;
Expand All @@ -189,9 +215,9 @@ const app = {
window.encodeHash();
},
renderAuthorShipTabHash(minDate, maxDate) {
renderAuthorShipTabHash(minDate: string, maxDate: string) {
const hash = window.hashParams;
const info = {
const info: AuthorshipInfo = {
author: hash.tabAuthor,
repo: hash.tabRepo,
isMergeGroup: hash.authorshipIsMergeGroup === 'true',
Expand All @@ -211,7 +237,7 @@ const app = {
renderZoomTabHash() {
const hash = window.hashParams;
const zoomInfo = {
const zoomInfo: ZoomInfo = {
isRefreshing: true,
zAuthor: hash.zA,
zRepo: hash.zR,
Expand Down Expand Up @@ -298,27 +324,7 @@ const app = {
return REPOS[hashParams.tabRepo].location.location;
},
},
computed: {
...mapState(['loadingOverlayCount', 'loadingOverlayMessage', 'isTabActive']),
},
components: {
LoadingOverlay,
cResizer,
cZoom,
cSummary,
cAuthorship,
},
created() {
try {
window.decodeHash();
} catch (error) {
this.userUpdated = false;
}
this.updateReportDir();
},
};
});
window.app = app;
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/types/vuex.d.ts
Expand Up @@ -10,25 +10,25 @@ interface AuthorshipInfo {
location: string | undefined;
maxDate: string;
minDate: string;
name: string;
name?: string;
repo: string;
}

interface ZoomInfo {
isRefreshing?: boolean;
zAuthor: string;
zAvgCommitSize: number | string;
zFileTypeColors: { [key: string]: string };
zFileTypeColors?: { [key: string]: string };
zFilterGroup: string;
zFilterSearch: string;
zFromRamp: boolean;
zIsMerged: boolean;
zLocation: string | undefined;
zLocation?: string | undefined;
zRepo: string;
zSince: string;
zTimeFrame: string;
zUntil: string;
zUser: User;
zUser?: User;
}

interface SummaryDates {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/types/window.ts
Expand Up @@ -68,5 +68,7 @@ declare global {
isSinceDateProvided: boolean;
isUntilDateProvided: boolean;
DOMAIN_URL_MAP: DomainUrlMap;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
app: any;
}
}
2 changes: 2 additions & 0 deletions frontend/src/types/zod/authorship-type.ts
Expand Up @@ -11,6 +11,8 @@ const fileResult = z.object({
fileType: z.string(),
lines: z.array(lineSchema),
authorContributionMap: z.record(z.number()),
isBinary: z.boolean().optional(),
isIgnored: z.boolean().optional(),
});

// Contains the zod validation schema for the authorship.json file
Expand Down

0 comments on commit 32d49ad

Please sign in to comment.