This repository has been archived by the owner on Apr 17, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 472
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
teams: migrated index page to vue components
- Loading branch information
1 parent
bb20213
commit 452ec54
Showing
30 changed files
with
572 additions
and
211 deletions.
There are no files selected for viewing
87 changes: 87 additions & 0 deletions
87
app/assets/javascripts/modules/teams/components/new-form.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import Vue from 'vue'; | ||
|
||
import { required } from 'vuelidate/lib/validators'; | ||
|
||
import EventBus from '~/utils/eventbus'; | ||
import Alert from '~/shared/components/alert'; | ||
import FormMixin from '~/shared/mixins/form'; | ||
|
||
import TeamsService from '../service'; | ||
|
||
const { set } = Vue; | ||
|
||
export default { | ||
template: '#js-new-team-form-tmpl', | ||
|
||
mixins: [FormMixin], | ||
|
||
data() { | ||
return { | ||
team: { | ||
name: '', | ||
}, | ||
timeout: { | ||
name: null, | ||
}, | ||
}; | ||
}, | ||
|
||
methods: { | ||
onSubmit() { | ||
TeamsService.save(this.team).then((response) => { | ||
const team = response.data; | ||
|
||
this.toggleForm(); | ||
this.$v.$reset(); | ||
set(this, 'team', { | ||
name: '', | ||
}); | ||
|
||
Alert.show(`Team '${team.name}' was created successfully`); | ||
EventBus.$emit('teamCreated', team); | ||
}).catch((response) => { | ||
let errors = response.data; | ||
|
||
if (Array.isArray(errors)) { | ||
errors = errors.join('<br />'); | ||
} | ||
|
||
Alert.show(errors); | ||
}); | ||
}, | ||
}, | ||
|
||
validations: { | ||
team: { | ||
name: { | ||
required, | ||
available(value) { | ||
clearTimeout(this.timeout.name); | ||
|
||
// required already taking care of this | ||
if (value === '') { | ||
return true; | ||
} | ||
|
||
return new Promise((resolve) => { | ||
const searchTeam = () => { | ||
const promise = TeamsService.exists(value); | ||
|
||
promise.then((exists) => { | ||
// leave it for the back-end | ||
if (exists === null) { | ||
resolve(true); | ||
} | ||
|
||
// if it doesn't exist, valid | ||
resolve(!exists); | ||
}); | ||
}; | ||
|
||
this.timeout.name = setTimeout(searchTeam, 1000); | ||
}); | ||
}, | ||
}, | ||
}, | ||
}, | ||
}; |
22 changes: 22 additions & 0 deletions
22
app/assets/javascripts/modules/teams/components/table-row.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
export default { | ||
template: '#js-team-table-row-tmpl', | ||
|
||
props: ['team', 'teamsPath'], | ||
|
||
computed: { | ||
scopeClass() { | ||
return `team_${this.team.id}`; | ||
}, | ||
|
||
teamIcon() { | ||
if (this.team.users_count > 1) { | ||
return 'fa-users'; | ||
} | ||
return 'fa-user'; | ||
}, | ||
|
||
teamPath() { | ||
return `${this.teamsPath}/${this.team.id}`; | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import getProperty from 'lodash/get'; | ||
|
||
import Comparator from '~/utils/comparator'; | ||
|
||
import TableSortableMixin from '~/shared/mixins/table-sortable'; | ||
import TablePaginatedMixin from '~/shared/mixins/table-paginated'; | ||
|
||
import TeamTableRow from './table-row'; | ||
|
||
export default { | ||
template: '#js-teams-table-tmpl', | ||
|
||
props: { | ||
teams: { | ||
type: Array, | ||
}, | ||
teamsPath: { | ||
type: String, | ||
}, | ||
prefix: { | ||
type: String, | ||
default: 'tm_', | ||
}, | ||
}, | ||
|
||
mixins: [TableSortableMixin, TablePaginatedMixin], | ||
|
||
components: { | ||
TeamTableRow, | ||
}, | ||
|
||
computed: { | ||
filteredTeams() { | ||
const order = this.sorting.asc ? 1 : -1; | ||
const sortedTeams = [...this.teams]; | ||
const sample = sortedTeams[0]; | ||
const value = getProperty(sample, this.sorting.by); | ||
const comparator = Comparator.of(value); | ||
|
||
// sorting | ||
sortedTeams.sort((a, b) => { | ||
const aValue = getProperty(a, this.sorting.by); | ||
const bValue = getProperty(b, this.sorting.by); | ||
|
||
return order * comparator(aValue, bValue); | ||
}); | ||
|
||
// pagination | ||
const slicedTeams = sortedTeams.slice(this.offset, this.limit * this.currentPage); | ||
|
||
return slicedTeams; | ||
}, | ||
}, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,2 @@ | ||
import './pages/index'; | ||
import './pages/show'; | ||
|
||
import TeamsIndexPage from './pages/index'; | ||
|
||
const TEAMS_INDEX_ROUTE = 'teams/index'; | ||
|
||
$(() => { | ||
const $body = $('body'); | ||
const route = $body.data('route'); | ||
|
||
if (route === TEAMS_INDEX_ROUTE) { | ||
// eslint-disable-next-line | ||
new TeamsIndexPage($body); | ||
} | ||
}); |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,50 @@ | ||
import BaseComponent from '~/base/component'; | ||
import Vue from 'vue'; | ||
|
||
import TeamsPanel from '../components/teams-panel'; | ||
import ToggleLink from '~/shared/components/toggle-link'; | ||
import EventBus from '~/utils/eventbus'; | ||
|
||
const TEAMS_PANEL = '.teams-wrapper'; | ||
import NewTeamForm from '../components/new-form'; | ||
import TeamsTable from '../components/table'; | ||
import TeamsStore from '../store'; | ||
|
||
// TeamsIndexPage component responsible to instantiate | ||
// the teams index page components and handle interactions. | ||
class TeamsIndexPage extends BaseComponent { | ||
elements() { | ||
this.$teamsPanel = this.$el.find(TEAMS_PANEL); | ||
} | ||
const { set } = Vue; | ||
|
||
mount() { | ||
this.teamsPanel = new TeamsPanel(this.$teamsPanel); | ||
$(() => { | ||
if (!$('body[data-route="teams/index"]').length) { | ||
return; | ||
} | ||
} | ||
|
||
export default TeamsIndexPage; | ||
// eslint-disable-next-line no-new | ||
new Vue({ | ||
el: 'body[data-route="teams/index"] .vue-root', | ||
|
||
components: { | ||
ToggleLink, | ||
NewTeamForm, | ||
TeamsTable, | ||
}, | ||
|
||
data() { | ||
return { | ||
state: TeamsStore.state, | ||
teams: window.teams, | ||
}; | ||
}, | ||
|
||
methods: { | ||
onCreate(team) { | ||
const currentTeams = this.teams; | ||
const teams = [ | ||
...currentTeams, | ||
team, | ||
]; | ||
|
||
set(this, 'teams', teams); | ||
}, | ||
}, | ||
|
||
mounted() { | ||
EventBus.$on('teamCreated', team => this.onCreate(team)); | ||
}, | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import Vue from 'vue'; | ||
import VueResource from 'vue-resource'; | ||
|
||
Vue.use(VueResource); | ||
|
||
const customActions = { | ||
teamTypeahead: { | ||
method: 'GET', | ||
url: 'teams/typeahead/{teamName}', | ||
}, | ||
}; | ||
|
||
const resource = Vue.resource('api/v1/teams{/id}', {}, customActions); | ||
|
||
function all(params = {}) { | ||
return resource.get({}, params); | ||
} | ||
|
||
function get(id) { | ||
return resource.get({ id }); | ||
} | ||
|
||
function save(team) { | ||
return resource.save({}, team); | ||
} | ||
|
||
function searchTeam(teamName) { | ||
return resource.teamTypeahead({ teamName }); | ||
} | ||
|
||
function exists(value) { | ||
return searchTeam(value) | ||
.then((response) => { | ||
const collection = response.data; | ||
|
||
if (Array.isArray(collection)) { | ||
return collection.some(e => e.name === value); | ||
} | ||
|
||
// some unexpected response from the api, | ||
// leave it for the back-end validation | ||
return null; | ||
}) | ||
.catch(() => null); | ||
} | ||
|
||
export default { | ||
get, | ||
all, | ||
save, | ||
exists, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
class TeamsStore { | ||
constructor() { | ||
this.state = { | ||
newFormVisible: false, | ||
editFormVisible: false, | ||
}; | ||
} | ||
} | ||
|
||
export default new TeamsStore(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
module Teams | ||
class CreateService < ::BaseService | ||
def execute | ||
@team = Team.new(params) | ||
@team.owners << current_user | ||
|
||
create_activity! if @team.save | ||
|
||
@team | ||
end | ||
|
||
private | ||
|
||
def create_activity! | ||
@team.create_activity(:create, | ||
owner: current_user, | ||
parameters: { team: @team.name }) | ||
end | ||
end | ||
end |
Oops, something went wrong.