...
 
Commits (23)
......@@ -14,10 +14,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Added
- work in progress on [ganttlab/ganttlab-live issues](https://gitlab.com/ganttlab/ganttlab-live/issues?scope=all&state=opened&utf8=%E2%9C%93&label_name%5B%5D=Feature)...
## 0.4.0 - 2016-12-05
### Added
- Now comes with integrated GitHub support
- Information about GitHub support in Readme
- work in progress on [ganttlab/ganttlab-live issues](https://gitlab.com/ganttlab/ganttlab-live/issues?scope=all&state=opened&utf8=%E2%9C%93&label_name%5B%5D=Feature)...
### Changed
- Refined look and feel, drastically improved login screen
- Styling has been moved from components to SCSS style sheets
### Fixed
- An edge case avoiding selection of a group project on large groups
- A white screen while paginated, due to lack of scroll to top behavior
- The useless scrolling after lowering number of issues expected per page
## 0.3.0 - 2016-11-24
### Added
- Width of Gantt chart is now calculated on browser window width, making it full screen
......@@ -88,4 +99,4 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- README includes a preview, and describes main topics to get started
- Initial vue-cli scaffolding with webpack plugin
[Unreleased]: https://gitlab.com/ganttlab/ganttlab-live/compare/v0.3.0...master
\ No newline at end of file
[Unreleased]: https://gitlab.com/ganttlab/ganttlab-live/compare/v0.4.0...master
\ No newline at end of file
# GanttLab
The easy to use, fully functional Gantt chart for GitLab.
The easy to use, fully functional Gantt chart for GitLab and GitHub.
![GanttLab](preview.png)
## Run it now!
It is already running live for you at https://live.ganttlab.org. Type-in your GitLab instance URL (works with https://gitlab.com), your GitLab account [_Private Token_](https://gitlab.com/profile/account) or a [_Personal Access Token_](https://gitlab.com/profile/personal_access_tokens) and enjoy!
It is already running live for you at https://live.ganttlab.org.
**Safe to run:** the application do NOT store any data, and runs on YOUR browser only, using your own network as if you were running all the requests to your GitLab instance right from your local computer. Unsure of it? Have a look at [the source code](https://gitlab.com/ganttlab/ganttlab-live/tree/master).
- **GitLab** user? Type-in your GitLab instance URL (works with https://gitlab.com), your GitLab account [_Private Token_](https://gitlab.com/profile/account) or a [_Personal Access Token_](https://gitlab.com/profile/personal_access_tokens) and enjoy!
- working on **GitHub**? Provide one of your GitHub user [Personal access tokens](https://github.com/settings/tokens) to get the ride!
**Safe to run:** the application do NOT store any data, and runs on YOUR browser only, using your own network as if you were running all the requests to your GitLab instance or to GitHub right from your local computer. Unsure of it? Have a look at [the source code](https://gitlab.com/ganttlab/ganttlab-live/tree/master).
**PRO tip:** if you are running an unsecured HTTP instance of GitLab, head to http://live.ganttlab.org to avoid your browser blocking the request coming from an HTTPS secured site.
## How it works
_GanttLab_ is a **frontend only** application. It leverages [GitLab awesome API](https://gitlab.com/help/api/README.md) to read your issues, before simply displaying a gantt chart with it.
_GanttLab_ is a **frontend only** application. It leverages [GitLab API](https://gitlab.com/help/api/README.md) or [GitHub API](https://developer.github.com/v3/) to read your issues, before simply displaying a Gantt chart with it.
The automatically generated [gantt chart](https://en.wikipedia.org/wiki/Gantt_chart) will display each of your issues within a "date area": from a **start date**, to the **due date**. For each issue, the **default start date** is read from the issue creation date. As with GitLab you are not forced to fill in a due date for your issues, the _GanttLab_ **default due date** will be set to the day after the issue creation date, faking all your issues having to be done in one day. For sure, if you insert a due date in your issues, it will be read automatically.
The automatically generated [Gantt chart](https://en.wikipedia.org/wiki/Gantt_chart) will display each of your issues within a "date area": from a **start date**, to the **due date**. For each issue, the **default start date** is read from the issue creation date. As with GitLab you are not forced to fill in a due date for your issues, and with GitHub you do not even have a due date on issues, the _GanttLab_ **default due date** will be set to the day after the issue creation date, faking all your issues having to be done in one day. For sure, if you insert a due date in your GitLab issues, it will be read automatically.
To give you maximum control over your issues and tasks management practices in the gantt chart, you can override this default values **right from your issue description** with two simple [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601#Calendar_dates) `YYYY-MM-DD` calendar dates:
......@@ -91,6 +94,7 @@ _GanttLab_ is an open source project: your contribution is very welcomed! Have a
- Moment.js http://momentjs.com/
- Evan You for being so clever on developing [Vue.js](http://vuejs.org/) and [vue-cli](https://github.com/vuejs/vue-cli)
- The [GitLab team](https://about.gitlab.com/team/) for this life changing product called [GitLab](https://about.gitlab.com/)
- [GitHub, Inc.](https://github.com/) for this incredibly useful and so widely used platform
## License
......
......@@ -19,7 +19,7 @@
<meta name="twitter:site" content="@GanttLab">
<meta name="twitter:creator" content="@GanttLab">
<meta name="twitter:title" content="GanttLab Live">
<meta name="twitter:description" content="The easy to use, fully functional Gantt chart for GitLab.">
<meta name="twitter:description" content="The easy to use, fully functional Gantt chart for GitLab and GitHub.">
<meta name="twitter:image" content="https://live.ganttlab.org/static/img/GanttLab.jpg">
<link href="https://fonts.googleapis.com/css?family=Anaheim%7CQuattrocento+Sans:400,400italic,700" rel="stylesheet" type="text/css">
</head>
......
{
"name": "ganttlab-live",
"version": "0.3.0",
"description": "The easy to use, fully functional Gantt chart for GitLab.",
"version": "0.4.0",
"description": "The easy to use, fully functional Gantt chart for GitLab and GitHub.",
"author": "clorichel <contact@clorichel.com>",
"private": false,
"scripts": {
......@@ -15,6 +15,7 @@
"lodash.debounce": "^4.0.8",
"moment": "^2.15.1",
"vue": "^2.0.1",
"vue-github-api": "^0.1.7",
"vue-gitlab-api": "^0.1.6",
"vue-multiselect": "^2.0.0-beta.10",
"vue-resource": "^1.0.3",
......
<template>
<div id="app">
<div id="App">
<transition name="fade">
<div v-if="failed == true || userEmpty" id="login">
<div v-if="loginFailed || !userName" id="LoginScreen">
<h1>GanttLab Live</h1>
<div class="row">
<div class="col welcome">
<div class="pad">
<h2>The easy to use, fully functional
<br/>Gantt chart for GitLab.</h2>
<br/>Gantt chart for GitLab and GitHub.</h2>
<p>Provide your teams with the right tool to master time and deadlines. Giving back credit to your project status and issues due dates has never been easier!</p>
<p v-if="userEmpty && downloading" class="downloading"><strong><i v-if="downloading" class="fa fa-circle-o-notch fa-spin" aria-hidden="true"></i> Connecting to {{ url }}</strong></p>
<p v-if="failed == true" class="error"><i class="fa fa-exclamation-triangle"></i> Unable to connect to {{ url }}</p>
<p v-if="!userName && downloading" class="downloading"><strong><i v-if="downloading" class="fa fa-circle-o-notch fa-spin" aria-hidden="true"></i> Connecting to {{ url }}</strong></p>
<p v-if="loginFailed" class="error"><i class="fa fa-exclamation-triangle"></i> Unable to connect to {{ url }}</p>
</div>
</div>
<div class="col form">
<p class="providerchoice"><i class="fa fa-gitlab" v-bind:class="{ selected: isGitLab }" v-on:click="providerName = 'GitLab'"></i><span> or </span><i class="fa fa-github" v-bind:class="{ selected: !isGitLab }" v-on:click="providerName = 'GitHub'"></i></p>
<p class="form-input first">
<input tabindex="1" v-model="url" v-on:keyup.enter="signin" autofocus>
<input tabindex="1" v-model="url" v-on:keyup.enter="signin" v-bind:disabled="providerName != 'GitLab'" v-bind:class="{ disabled: providerName != 'GitLab' }" autofocus>
</p>
<p class="helper">Your GitLab instance URL</p>
<p class="helper" v-bind:class="{ disabled: providerName != 'GitLab' }">Your GitLab instance URL</p>
<p class="form-input">
<input tabindex="2" v-model="token" v-on:keyup.enter="signin">
</p>
<p class="helper">Use your <a v-bind:href="privateTokenLink" target="_blank" title="/profile/account">Private Token</a>, or a <a v-bind:href="personalTokenLink" target="_blank" title="/profile/personal_access_tokens">Personal Access Token</a></p>
<p v-if="providerName == 'GitLab'" class="helper">Use your <a v-bind:href="privateTokenLink" target="_blank" title="/profile/account">Private Token</a>, or a <a v-bind:href="personalTokenLink" target="_blank" title="/profile/personal_access_tokens">Personal Access Token</a></p>
<p v-else class="helper">Use one of your <a href="https://github.com/settings/tokens" target="_blank" title="https://github.com/settings/tokens">Personal Access Tokens</a></p>
<p v-if="hasLocalStorage" class="form-input remember"><input tabindex="3" type="checkbox" v-model="rememberMe"> <span>Remember me <i class="fa fa-question-circle-o" aria-hidden="true" title="Don't do that on a public computer!"></i></span> <button tabindex="4" v-on:click="signin">Sign-in &nbsp;&gt;</button></p>
</div>
......@@ -49,51 +51,113 @@
</div>
</transition>
<transition name="fade">
<div v-if="!userEmpty" id="screen">
<div v-if="userName" id="MainScreen">
<div id="top" class="standardpadding">
<div v-if="!userEmpty">
<span class="user"><img v-bind:src="GitLab.user.avatar_url"> {{ GitLab.user.name }}</span>
<div v-if="userName">
<span class="user"><img v-bind:src="userAvatarUrl"> {{ userName }}</span>
<span class="server"><transition name="fade"><i v-if="downloading" class="fa fa-circle-o-notch fa-spin downloading" aria-hidden="true"></i></transition> <a v-bind:href="url" target="_blank">{{ url }}</a> <a href="https://gitlab.com/ganttlab/ganttlab-live#how-it-works" target="_blank"><i class="fa fa-question-circle" aria-hidden="true" title="Help"></i></a> <i class="fa fa-times close" aria-hidden="true" v-on:click="logout" title="Close"></i></span>
</div>
</div>
<mainFilter v-bind:user="GitLab.user" v-bind:downloading="downloading"></mainFilter>
<component v-bind:is="provider" class="provider"></component>
<div class="standardpadding">
<p v-if="downloading" class="downloading"><i class="fa fa-circle-o-notch fa-spin" aria-hidden="true"></i></p>
<gantt v-if="tasks != null"></gantt>
</div>
<div v-if="! downloading && (this.paginationLinks.prev || this.paginationLinks.next)" class="pagination">
<button v-if="this.paginationLinks.prev" v-on:click="paginationPage--">&lt; Prev</button>
<span>Page {{ this.paginationPage }}</span>
<button v-if="this.paginationLinks.next" v-on:click="paginationPage++">Next &gt;</button>
<div class="perpage">
Showing
<select v-model="paginationPerPage">
<option v-for="value in [10,20,50,75,100]" v-bind:value="value">{{ value }}</option>
</select>
issues per page
</div>
</div>
</div>
</transition>
</div>
</template>
<script>
import MainFilter from './components/MainFilter'
import SharedStates from './mixins/SharedStates'
import Gantt from './components/Gantt'
import 'font-awesome/css/font-awesome.css'
export default {
name: 'app',
mixins: [
SharedStates
],
components: {
Gantt
},
data () {
return {
rememberMe: false,
url: process.env.GITLAB_URL,
token: process.env.GITLAB_TOKEN,
GitLab: {
user: {} // need to be defined here, or computed property won't work as expected
},
failed: false
providerName: 'GitLab',
provider: null
}
},
components: {
MainFilter
computed: {
isGitLab: function () {
return this.providerName === 'GitLab'
},
safeUrl: function () {
if (this.url == null) {
return null
}
return this.url.replace(/\/$/, '')
},
privateTokenLink: function () {
return this.safeUrl + '/profile/account'
},
personalTokenLink: function () {
return this.safeUrl + '/profile/personal_access_tokens'
},
hasLocalStorage: function () {
return typeof Storage !== 'undefined'
}
},
methods: {
getGitLabUser: function (event) {
this.GitLabAPI.get('/user', [], [this.GitLab, 'user'], (response) => {
this.failed = true
this.GitLabAPI.get('/user', [], (response) => {
this.userName = response.body.name
this.userAvatarUrl = response.body.avatar_url
this.provider = require('./components/providers/GitLab')
}, (response) => {
this.loginFailed = true
})
},
getGitHubUser: function (event) {
this.GitHubAPI.get('/user', [], (response) => {
this.userName = response.body.login
this.userAvatarUrl = response.body.avatar_url
this.provider = require('./components/providers/GitHub')
}, (response) => {
this.loginFailed = true
})
},
signin: function (event) {
this.GitLab.user = {}
this.failed = false
this.GitLabAPI.setUrl(this.url)
this.GitLabAPI.setToken(this.token)
this.getGitLabUser()
this.userName = null
this.userAvatarUrl = null
this.loginFailed = false
if (this.providerName === 'GitLab') {
this.GitLabAPI.registerStore(this.$store)
this.GitLabAPI.setUrl(this.url)
this.GitLabAPI.setToken(this.token)
this.getGitLabUser()
} else {
this.GitHubAPI.registerStore(this.$store)
this.GitHubAPI.setToken(this.token)
this.getGitHubUser()
this.url = 'https://github.com'
}
if (this.hasLocalStorage) {
if (this.rememberMe) {
window.localStorage.url = this.url
......@@ -108,8 +172,9 @@ export default {
},
logout: function (event) {
window.history.pushState(null, null, '/')
this.GitLab.user = {}
this.failed = false
this.userName = null
this.userAvatarUrl = null
this.loginFailed = false
if (!this.rememberMe) {
this.token = ''
if (this.hasLocalStorage) {
......@@ -120,32 +185,9 @@ export default {
}
}
},
computed: {
userEmpty: function () {
return !(this.GitLab.hasOwnProperty('user') && this.GitLab.user.hasOwnProperty('name'))
},
downloading: function () {
if (typeof this.$store.state.GitLabAPI !== 'undefined') {
return this.$store.state.GitLabAPI.downloading
} else {
return false
}
},
safeUrl: function () {
return this.url.replace(/\/$/, '')
},
privateTokenLink: function () {
return this.safeUrl + '/profile/account'
},
personalTokenLink: function () {
return this.safeUrl + '/profile/personal_access_tokens'
},
hasLocalStorage: function () {
return typeof Storage !== 'undefined'
}
},
mounted: function () {
this.GitLabAPI.registerStore(this.$store)
this.url = process.env.GITLAB_URL
this.token = process.env.GITLAB_TOKEN
if (this.hasLocalStorage) {
this.url = window.localStorage.getItem('url') || process.env.GITLAB_URL
this.token = window.localStorage.getItem('token') || process.env.GITLAB_TOKEN
......
@import "ganttlab/variables";
@import "ganttlab/app";
@import "ganttlab/selector";
@import "ganttlab/providers";
@import "ganttlab/gantt";
\ No newline at end of file
......@@ -2,7 +2,7 @@ body {
margin: 0;
padding: 0;
}
#app {
#App {
font-family: $main-font;
-webkit-font-smoothing: antialiased;
color: $text-color;
......@@ -26,7 +26,7 @@ a:hover {
display: table-column;
width: 200px;
}
#login {
#LoginScreen {
width: 60%;
font-size: 20px;
position: absolute;
......@@ -35,61 +35,62 @@ a:hover {
transform: translateX(-50%) translateY(-50%);
display: table;
}
#login .row{
#LoginScreen .row{
display:table-row;
width:auto;
clear:both;
}
#login .welcome {
#LoginScreen .welcome {
margin-top: 2rem;
width: 60%;
display: inline-block;
font-size: 16px;
}
#login .welcome .pad {
#LoginScreen .welcome .pad {
padding: 0px 40px;
}
#login .form {
#LoginScreen .form {
display: inline-block;
width: 40%;
}
#login h1 {
#LoginScreen h1 {
font-size: 2.375rem;
text-align: left;
border-bottom: 1px solid rgba(21, 21, 21, 0.05);
padding: 0 0 0.5rem 1rem;
margin: 0 0 2rem;
margin: 0 0 1rem;
}
#login h2 {
#LoginScreen h2 {
font-size: 1.375rem;
margin-bottom: 30px;
}
#login .error,
#login .downloading {
#LoginScreen .error,
#LoginScreen .downloading {
text-align: center;
margin-top: 30px;
font-size: 1rem;
}
#login .error {
#LoginScreen .error {
color: #a94442;
}
#login input,
#login input[type="checkbox"] {
#LoginScreen input,
#LoginScreen input[type="checkbox"] {
font-family: $main-font;
border: 1px solid rgba(21, 21, 21, 0.1);
border-radius: 2px;
transition: all ease-in-out 0.15s;
}
#login .form-input.first {
margin-top: 1.7rem;
#LoginScreen .form-input.first {
margin-top: 5px;
}
#login .form-input input:focus,
#login input[type="checkbox"]:focus,
#login button:focus {
#LoginScreen .form-input input:focus,
#LoginScreen input[type="checkbox"]:focus,
#LoginScreen button:focus {
outline: none;
border-color: #00b3e6;
box-shadow: 0 0 5px #00b3e6;
}
#login .form-input input {
#LoginScreen .form-input input {
display: inline-block;
width: 90%;
height: 34px;
......@@ -101,21 +102,24 @@ a:hover {
background-image: none;
height: 20px;
}
#login .form-input.remember {
#LoginScreen .form-input input.disabled {
color: rgba(#555, 0.5);
}
#LoginScreen .form-input.remember {
text-align: left;
margin-top: 2rem;
}
#login .form-input.remember span {
#LoginScreen .form-input.remember span {
font-size: 1rem;
}
#login .form-input.remember input {
#LoginScreen .form-input.remember input {
height: 13px;
}
#login .form-input.remember span,
#login .form-input.remember input {
#LoginScreen .form-input.remember span,
#LoginScreen .form-input.remember input {
width: auto;
}
#login .form-input.remember button {
#LoginScreen .form-input.remember button {
background-color: rgba($lead-color, 1);
color: #fff;
font-family: $lead-font;
......@@ -130,9 +134,26 @@ a:hover {
float: right;
transition: all ease-in-out 0.15s;
}
#login .form-input.remember button:hover {
#LoginScreen .form-input.remember button:hover {
background-color: rgba($lead-color, 0.8);
}
.providerchoice {
margin: 0px;
font-size: 2em;
text-align: center;
}
.providerchoice span {
font-size: 0.4em;
margin: 0 20px;
}
.providerchoice i {
transition: color 0.2s;
cursor: pointer;
color: rgba($text-color, 0.3);
}
.providerchoice i.selected {
color: $text-color;
}
.helper {
text-align: left;
font-size: 0.62em;
......@@ -144,9 +165,12 @@ a:hover {
.helper a:hover {
text-decoration: none;
}
.helper.disabled {
color: rgba($text-color, 0.5)
}
.more {
border-top: 1px solid rgba(21, 21, 21, 0.05);
margin-top: 2rem;
margin-top: 1rem;
}
.col.copy,
.col.social {
......@@ -220,4 +244,26 @@ a:hover {
}
.fade-enter, .fade-leave-active {
opacity: 0
}
.pagination {
text-align: center;
}
.pagination span {
margin: 0 20px;
}
.perpage {
margin-top: 20px;
text-align: center;
font-size: 0.8em;
}
button {
border: 1px solid #bbb;
padding: 2px 4px 0;
margin: 0;
font: inherit;
outline:none;
line-height: 1.2;
background: #f8f8f8;
border-radius: 4px;
cursor: pointer;
}
\ No newline at end of file
#Gantt {
font-family: $main-font;
}
.rect_has_data {
/* blocks that have data */
fill: #5cb85c;
......@@ -16,17 +20,17 @@
fill: #c9302c;
}
.tooltip_has_data {
/* color of symbol in tooltip if there is data */
.taskTooltip_has_data {
/* color of symbol in taskTooltip if there is data */
color: #449d44;
}
.tooltip_has_no_data {
/* color of symbol in tooltip if there is no data */
.taskTooltip_has_no_data {
/* color of symbol in taskTooltip if there is no data */
color: #c9302c;
}
div.tooltip {
div.taskTooltip {
font-family: $main-font;
position: absolute;
text-align: left;
......
......@@ -2,22 +2,13 @@
text-align: center;
font-size: 2.5em;
}
#mainfilter {
.provider {
font-family: $lead-font;
margin: 0;
padding: 8px;
background-color:#fafafa;
border-bottom: 1px solid #e5e5e5;
top: 0;
left: 0;
height: 26px;
line-height: 26px;
text-align: center;
}
#mainfilter input[type=radio] {
.provider input[type=radio] {
display:none;
}
#mainfilter input[type=radio] + label {
.provider input[type=radio] + label {
display:inline-block;
margin:-2px;
padding: 4px 12px;
......@@ -28,7 +19,7 @@
border-bottom: 2px solid #fafafa;
color: #777;
}
#mainfilter input[type=radio]:checked + label {
.provider input[type=radio]:checked + label {
border-bottom: 2px solid $lead-color;
color: #2c3e50;
}
......@@ -39,6 +30,17 @@
font-size: 0.8em;
cursor: pointer;
}
.filter {
padding: 8px;
margin: 0;
background-color:#fafafa;
border-bottom: 1px solid #e5e5e5;
top: 0;
left: 0;
height: 26px;
line-height: 26px;
text-align: center;
}
.subfilter {
margin: 0;
padding: 8px;
......@@ -70,26 +72,4 @@
.group-separator {
font-weight: bold;
font-size: 1.5em;
}
.pagination {
text-align: center;
}
.pagination span {
margin: 0 20px;
}
.perpage {
margin-top: 20px;
text-align: center;
font-size: 0.8em;
}
button {
border: 1px solid #bbb;
padding: 2px 4px 0;
margin: 0;
font: inherit;
outline:none;
line-height: 1.2;
background: #f8f8f8;
border-radius: 4px;
cursor: pointer;
}
\ No newline at end of file
<template>
<div id="gantt">
<div id="Gantt">
<p v-if="tasks.length == 0">No tasks out there...</p>
<div v-if="tasks.length > 0" id="chart"></div>
</div>
......@@ -11,14 +11,16 @@ import moment from 'moment'
export default {
name: 'gantt',
props: [
'tasks'
],
data () {
return {
//
}
},
computed: {
tasks: function () {
return this.$store.state.tasks
}
},
watch: {
tasks: function (newTasks) {
this.refreshChart()
......@@ -73,9 +75,9 @@ export default {
// "curDisplayFirstDataset+maxDisplayDatasets"
var curDisplayFirstDataset = 0
// global div for tooltip
// global div for taskTooltip
var div = d3.select('body').append('div')
.attr('class', 'tooltip')
.attr('class', 'taskTooltip')
.style('opacity', 0)
var definedBlocks = null
......@@ -344,9 +346,9 @@ export default {
div.html(function () {
var output = ''
if (d[1] === 1) {
output = '<i class="fa fa-fw fa-check tooltip_has_data"></i>'
output = '<i class="fa fa-fw fa-check taskTooltip_has_data"></i>'
} else {
output = '<i class="fa fa-fw fa-times tooltip_has_no_data"></i>'
output = '<i class="fa fa-fw fa-times taskTooltip_has_no_data"></i>'
}
if (isDateOnlyFormat) {
if (d[2] > d3.time.second.offset(d[0], 86400)) {
......@@ -559,6 +561,12 @@ export default {
return chart
},
refreshChart: function (event) {
// removing all created taskTooltips to avoid useless scrolling
var paras = document.getElementsByClassName('taskTooltip')
while (paras[0]) {
paras[0].parentNode.removeChild(paras[0])
}
var chart = this.visavailChart().width(document.body.clientWidth - 290)
d3.select('#chart')
......
This diff is collapsed.
......@@ -6,12 +6,53 @@ Vue.use(Vuex)
import VueResource from 'vue-resource'
Vue.use(VueResource)
import GitHubAPI from 'vue-github-api'
Vue.use(GitHubAPI)
import GitLabAPI from 'vue-gitlab-api'
Vue.use(GitLabAPI)
import App from './App'
const store = new Vuex.Store({})
const store = new Vuex.Store({
state: {
url: null,
token: null,
loginFailed: false,
user: {
name: null,
avatarUrl: null
},
tasks: null,
pagination: {
page: 1,
perPage: 100,
links: {
prev: null,
next: null
}
}
},
mutations: {
url: function (state, value) {
state.url = value
},
token: function (state, value) {
state.token = value
},
loginFailed: function (state, value) {
state.loginFailed = value
},
user: function (state, value) {
state.user = value
},
tasks: function (state, value) {
state.tasks = value
},
pagination: function (state, value) {
state.pagination = value
}
}
})
/* eslint-disable no-new */
new Vue({
......
module.exports = {
computed: {
downloading: function () {
if (typeof this.$store.state.GitLabAPI !== 'undefined') {
return this.$store.state.GitLabAPI.downloading
} else if (typeof this.$store.state.GitHubAPI !== 'undefined') {
return this.$store.state.GitHubAPI.downloading
} else {
return false
}
},
url: {
get () {
return this.$store.state.url
},
set (value) {
this.$store.commit('url', value)
}
},
token: {
get () {
return this.$store.state.token
},
set (value) {
this.$store.commit('token', value)
}
},
loginFailed: {
get () {
return this.$store.state.loginFailed
},
set (value) {
this.$store.commit('loginFailed', value)
}
},
userName: {
get () {
return this.$store.state.user.name
},
set (value) {
var user = this.$store.state.user
user.name = value
this.$store.commit('user', user)
}
},
userAvatarUrl: {
get () {
return this.$store.state.user.avatarUrl
},
set (value) {
var user = this.$store.state.user
user.avatarUrl = value
this.$store.commit('user', user)
}
},
tasks: function () {
return this.$store.state.tasks
},
paginationPage: {
get () {
return this.$store.state.pagination.page
},
set (value) {
var pagination = this.$store.state.pagination
pagination.page = value
this.$store.commit('pagination', pagination)
}
},
paginationPerPage: {
get () {
return this.$store.state.pagination.perPage
},
set (value) {
var pagination = this.$store.state.pagination
pagination.perPage = value
this.$store.commit('pagination', pagination)
}
},
paginationLinks: {
get () {
return this.$store.state.pagination.links
},
set (value) {
var pagination = this.$store.state.pagination
pagination.links = value
this.$store.commit('pagination', pagination)
}
}
}
}