Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6,556 changes: 4,312 additions & 2,244 deletions package-lock.json

Large diffs are not rendered by default.

73 changes: 37 additions & 36 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,49 +16,50 @@
"sonar": "sonar-scanner"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.15",
"@fortawesome/free-solid-svg-icons": "^5.7.2",
"@fortawesome/vue-fontawesome": "^0.1.5",
"axios": "^0.18.0",
"bootstrap": "^4.3.1",
"bootstrap-vue": "^2.0.0-rc.14",
"bootswatch": "^4.3.1",
"core-js": "^2.6.5",
"@fortawesome/fontawesome-svg-core": "^1.2.26",
"@fortawesome/free-solid-svg-icons": "^5.12.0",
"@fortawesome/vue-fontawesome": "^0.1.8",
"axios": "^0.19.0",
"bootstrap": "^4.4.1",
"bootstrap-vue": "^2.1.0",
"bootswatch": "^4.4.1",
"core-js": "^3.5.0",
"moment": "^2.24.0",
"vue": "2.6.8",
"vue-class-component": "^7.0.1",
"vue-property-decorator": "^8.0.0",
"vue-router": "^3.0.2"
"npm-check-updates": "^4.0.1",
"vue": "2.6.10",
"vue-class-component": "^7.1.0",
"vue-property-decorator": "^8.3.0",
"vue-router": "^3.1.3"
},
"devDependencies": {
"@types/jest": "^24.0.9",
"@vue/test-utils": "^1.0.0-beta.29",
"axios-mock-adapter": "^1.16.0",
"clean-webpack-plugin": "^2.0.0",
"css-loader": "^2.1.1",
"file-loader": "^3.0.1",
"git-revision-webpack-plugin": "^3.0.3",
"@types/jest": "^24.0.23",
"@vue/test-utils": "^1.0.0-beta.30",
"axios-mock-adapter": "^1.17.0",
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^3.3.0",
"file-loader": "^5.0.2",
"git-revision-webpack-plugin": "^3.0.4",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"jest": "^24.3.1",
"jsdom": "^13.2.0",
"jest": "^24.9.0",
"jsdom": "^15.2.1",
"jsdom-global": "^3.0.2",
"less": "^3.9.0",
"less-loader": "^4.1.0",
"sonarqube-scanner": "^2.4.0",
"string-replace-loader": "^2.1.1",
"ts-jest": "^24.0.0",
"ts-loader": "^5.3.3",
"tslint": "^5.13.1",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"sonarqube-scanner": "^2.5.0",
"string-replace-loader": "^2.2.0",
"ts-jest": "^24.2.0",
"ts-loader": "^6.2.1",
"tslint": "^5.20.1",
"tslint-loader": "^3.5.4",
"tslint-webpack-plugin": "^2.0.3",
"typescript": "^3.3.3",
"tslint-webpack-plugin": "^2.1.0",
"typescript": "^3.7.3",
"vue-jest": "^4.0.0-beta.2",
"vue-loader": "^15.7.0",
"vue-template-compiler": "2.6.8",
"webpack": "^4.29.6",
"webpack-cli": "^3.2.3",
"webpack-dev-server": "^3.2.1",
"webpack-merge": "^4.2.1"
"vue-loader": "^15.7.2",
"vue-template-compiler": "2.6.10",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0",
"webpack-merge": "^4.2.2"
}
}
1 change: 1 addition & 0 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

<b-collapse is-nav id="nav_collapse">
<b-navbar-nav>
<b-nav-item to="/dashboard">Dashboard</b-nav-item>
<b-nav-item to="/git-users">Git Users</b-nav-item>
<b-nav-item to="/configurations">Configurations</b-nav-item>
</b-navbar-nav>
Expand Down
5 changes: 2 additions & 3 deletions src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import "bootstrap/dist/css/bootstrap.css";
import "bootswatch/dist/flatly/bootstrap.min.css";

// IE polyfills
import "core-js/es6/array";
import "core-js/es6/string";
import "core-js/es7/array";
import "core-js/es/array";
import "core-js/es/string";

// Main Vue library
import Vue from "vue";
Expand Down
9 changes: 9 additions & 0 deletions src/common/filters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ Vue.filter("customDateFilter", (timestamp: number) => {
return moment(timestamp).format("YYYY-MM-DD HH:mm:ss");
}
});

Vue.filter("timeFromNow", (timestamp: number) => {
if (timestamp === 0) {
return "--";
} else {
return moment(timestamp).fromNow();
}
});

31 changes: 31 additions & 0 deletions src/components/Stats/Stats.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<template>
<div>Open Pull Requests from Bot/Total: <span class="font-weight-bold">{{amountOpenPullRequest}} / {{totalOpenPullRequest}}</span></div>
</template>

<script lang="ts">
import {Component, Prop, Vue} from "vue-property-decorator";
import IConfiguration from "../../views/configurations/Configuration.interface";
import StatsRestClient from "./StatsRestClient";

@Component({})
export default class Stats extends Vue {
@Prop() configuration: IConfiguration;
private amountOpenPullRequest = "";
private totalOpenPullRequest = "";

public async mounted() {
await this.getOpenPullRequests(this.configuration.configurationId);
}

public async getOpenPullRequests(configId) {
let stats = await StatsRestClient.getAmountOpenPullRequest(configId);
this.amountOpenPullRequest = stats.amount;
this.totalOpenPullRequest = stats.total;
}

}
</script>

<style scoped>

</style>
14 changes: 14 additions & 0 deletions src/components/Stats/StatsRestClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// A RestClient to interact with Configuration API resources
import axios from "axios";
import config from "../../config";

export default abstract class StatsRestClient {
// Get amount of open Pull Requests by configuration ID
public static async getAmountOpenPullRequest(
configId: bigint
): Promise<any> {
return (await axios.get(`${this.api}/configurations/${configId}/openPullRequests`)).data;
}

private static api = config.apiEndpoint;
}
199 changes: 199 additions & 0 deletions src/components/Timeline/Timeline.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
<template>
<b-container class="tab-content" fluid>

<b-list-group class="event-group">
<div class="update-header">
<p>Last updated: {{lastUpdate | customDateFilter}}</p>
<b-button variant="primary" style="float:right;"
@click.prevent="fetchEvents(configuration.configurationId)">
Update Events
</b-button>
</div>
<b-list-group-item class="" v-for="event in events" :key="'event-' + event.id">
<!-- Pull Request Events -->
<div v-if="event.type === eventTypes[0]">
<div>
<div class="event-item-header">
<div class="event-item-header-title h5">
<a :href="event.payload.pull_request._links.html.href"
target="_blank">
{{event.payload.pull_request.title}}
</a>
</div>
</div>
<div class="event-body">
<div :class="eventItemStatus(event)">{{event.payload.pull_request.state}}
<span class="font-weight-bold">Pull Request</span></div>
<div class="event-item-time">
<div v-if="event.payload.pull_request.merged_at !== null">
merged
<time v-b-tooltip :title="event.payload.pull_request.merged_at | customDateFilter" :datetime="event.payload.pull_request.merged_at">
{{event.payload.pull_request.merged_at | timeFromNow}}
</time>
</div>
<div v-else-if="event.payload.pull_request.closed_at !== null">
closed
<time v-b-tooltip :title="event.payload.pull_request.closed_at | customDateFilter" :datetime="event.payload.pull_request.closed_at">
{{event.payload.pull_request.closed_at | timeFromNow}}
</time>
</div>
<div v-else-if="event.payload.pull_request.updated_at !== null">
updated
<time v-b-tooltip :title="event.payload.pull_request.updated_at | customDateFilter"
:datetime="event.payload.pull_request.updated_at">
{{event.payload.pull_request.updated_at | timeFromNow}}
</time>
</div>
<div v-else-if="event.payload.pull_request.created_at !== null">
created
<time v-b-tooltip :title="event.payload.pull_request.created_at| customDateFilter"
:datetime="event.payload.pull_request.created_at">
{{event.payload.pull_request.created_at | timeFromNow}}
</time>
</div>
</div>
<div class="event-item-actor">by <a
:href="event.payload.pull_request.user.html_url"
target="_blank">{{event.actor.login}}</a>
</div>
</div>
</div>
</div>
<!-- Issue Comment Events -->
<div v-else-if="event.type === eventTypes[1]">
<div>
<div class="event-item-actor"><a :href="event.payload.comment.user.html_url"
target="_blank"> {{event.actor.login}}</a>
</div>
<div class="event-item-time">
<div v-if="event.payload.comment.created_at !== null">
commented

<time v-b-tooltip :title="event.payload.comment.created_at | customDateFilter" :datetime="event.payload.comment.created_at">
{{event.payload.comment.created_at | timeFromNow}}
</time>
</div>
</div>
<blockquote class="event-item-comment"><p>{{event.payload.comment.body}}</p>
</blockquote>
<div>in <a :href="event.payload.issue.html_url"
target="_blank">{{event.payload.issue.title}}</a>
</div>
</div>
</div>
</b-list-group-item>
</b-list-group>


</b-container>
</template>

<script lang="ts">
import {Component, Prop, Vue} from "vue-property-decorator";
import IConfiguration from "../../views/configurations/Configuration.interface";
import IGitUser from "../../views/git-users/GitUser.interface";
import TimelineRestClient from "./TimelineRestClient";

@Component({
filters: {
author: function (v) {
const newline = v.indexOf("\n");
return newline > 0 ? v.slice(0, newline) : v;
}
}
})
export default class Timeline extends Vue {
@Prop() configuration: IConfiguration;
private gitUser = {} as IGitUser;
private events = [];
private eventTypes = ["PullRequestEvent", "IssueCommentEvent"];
private lastUpdate = "";

public async mounted() {
await this.init();
}

public async init() {
// Fetch items from API
await this.fetchEvents(this.configuration.configurationId);
}

eventFilter(events) {
if ((this.eventTypes[0] === events.type) && (events.actor.login === this.configuration.botName)) {
return (events.type);
}
if ((this.eventTypes[1]) === events.type && ((events.actor.login === this.configuration.botName) || (events.payload.issue.user.login === this.configuration.botName))){
return (events.type);
}
}

public async fetchEvents(configId) {
this.events = await TimelineRestClient.getConfigEvents(configId);
this.events = this.events.filter(this.eventFilter);
this.lastUpdate = new Date().toISOString();
this.$bvToast.toast('Events are updated', {
variant: 'primary',
toaster: 'b-toaster-top-center',
autoHideDelay: 1800
})
}

eventItemStatus(event) {
switch (event.payload.pull_request.state){
case "closed": {
return "event-item-state--closed";
}
case "open": {
return "event-item-state--open";
}
case "merged": {
return "event-item-state--merged"
}
}
}
}
</script>

<style lang="less" scoped>

.tab-content {
padding-top: 15px;
}

.update-header {
align-self: flex-end;
padding-right: 10px;
}

.event-group {
overflow-y: auto;
max-height: 50vh;
}

.event-item {
&-state {
&--closed {
color: red;
}

&--open {
color: dodgerblue;
}

&--merged {
color: green;
}
}

&-time, &-status, &-actor {
display: inline-block;
}

&-comment {
background: #f9f9f9;
border-left: 10px solid #ccc;
padding: 5px;
font-size: 12pt;
}
}
</style>
21 changes: 21 additions & 0 deletions src/components/Timeline/TimelineRestClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// A RestClient to interact with GitHub Event API resources
import axios from "axios";
import config from "../../config";

export default abstract class TimelineRestClient {
// Get events by GitUserID
public static async getUserEvents(
gitUserId: bigint
): Promise<any> {
return (await axios.get(`${this.api}/git-users/${gitUserId}/events`)).data;
}

// Get events by configID
public static async getConfigEvents(
configId: bigint
): Promise<any> {
return (await axios.get(`${this.api}/configurations/${configId}/events`)).data;
}

private static api = config.apiEndpoint;
}
Loading