Skip to content

Commit

Permalink
feat(repositories): search implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jkuri committed Jul 30, 2017
1 parent b304161 commit 613d1d6
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 15 deletions.
8 changes: 6 additions & 2 deletions src/api/db/repository.ts
Expand Up @@ -87,9 +87,13 @@ export function getRepositoryByBuildId(buildId: number): Promise<any> {
}); });
} }


export function getRepositories(userId: string): Promise<any[]> { export function getRepositories(userId: string, keyword: string): Promise<any[]> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
new Repository().fetchAll().then(repos => { new Repository().query(qb => {
if (keyword !== '') {
qb.where('full_name', 'like', `%${keyword}%`).orWhere('clone_url', 'like', `%${keyword}%`);
}
}).fetchAll().then(repos => {
if (!repos) { if (!repos) {
reject(); reject();
} }
Expand Down
2 changes: 1 addition & 1 deletion src/api/server-routes.ts
Expand Up @@ -104,7 +104,7 @@ export function repositoryRoutes(): express.Router {
const router = express.Router(); const router = express.Router();


router.get('/', (req: express.Request, res: express.Response) => { router.get('/', (req: express.Request, res: express.Response) => {
getRepositories('1').then(repos => { getRepositories(req.query.userId, req.query.keyword).then(repos => {
return res.status(200).json({ data: repos }); return res.status(200).json({ data: repos });
}).catch(err => res.status(200).json({ status: false })); }).catch(err => res.status(200).json({ status: false }));
}); });
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/app-job/app-job.component.html
Expand Up @@ -15,7 +15,7 @@
<div class="columns is-multiline"> <div class="columns is-multiline">
<div class="column is-9"> <div class="column is-9">
<h1 class="bold"> <h1 class="bold">
<span><a [routerLink]="['/repo', job?.builds_id]">{{ job?.build.head_full_name }}</a></span> <span><a [routerLink]="['/repo', job?.build.repository.id]">{{ job?.build.head_full_name }}</a></span>
<span class="build-icon"> <span class="build-icon">
<img src="images/icons/clock.svg" *ngIf="job?.status === 'queued'"> <img src="images/icons/clock.svg" *ngIf="job?.status === 'queued'">
<img src="images/icons/flickr.svg" *ngIf="job?.status === 'running'"> <img src="images/icons/flickr.svg" *ngIf="job?.status === 'running'">
Expand Down
Expand Up @@ -9,9 +9,21 @@ <h1>Repositories</h1>
</div> </div>
<div class="nav-center"></div> <div class="nav-center"></div>
<div class="nav-right"> <div class="nav-right">
<div class="group-buttons"> <div class="search-input-container">
<button class="group-button is-active">Repositories</button> <input type="text" class="search-input" placeholder="Search" [(ngModel)]="searchKeyword" (ngModelChange)="onKeywordChanged($event)">
<button class="group-button">All Repositories</button> <svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g transform="translate(-1376.000000, -97.000000)" fill="#A1A7AF">
<g transform="translate(0.000000, 70.000000)">
<g transform="translate(1136.000000, 17.000000)">
<g>
<path d="M250.5355,13.4645 C248.5825,11.5115 245.4175,11.5115 243.4645,13.4645 C241.5115,15.4175 241.5115,18.5825 243.4645,20.5355 C245.4175,22.4885 248.5825,22.4885 250.5355,20.5355 C252.4885,18.5825 252.4885,15.4175 250.5355,13.4645 M255.7355,25.7355 C255.3445,26.1255 254.7115,26.1255 254.3205,25.7355 L251.1715,22.5855 C248.4295,24.6355 244.5415,24.4415 242.0505,21.9495 C239.3165,19.2165 239.3165,14.7845 242.0505,12.0505 C244.7835,9.3165 249.2165,9.3165 251.9495,12.0505 C254.4415,14.5415 254.6355,18.4295 252.5855,21.1715 L255.7355,24.3215 C256.1255,24.7115 256.1255,25.3445 255.7355,25.7355" id="Icon"></path>
</g>
</g>
</g>
</g>
</g>
</svg>
</div> </div>
</div> </div>
</div> </div>
Expand All @@ -27,11 +39,8 @@ <h1>Repositories</h1>


<div class="columns is-multiline" *ngIf="!loading"> <div class="columns is-multiline" *ngIf="!loading">
<div class="column is-12" *ngIf="!repositories || !repositories.length"> <div class="column is-12" *ngIf="!repositories || !repositories.length">
<div class="notification"> <div class="notification is-info">
<span class="icon"> No repositories found.
<img src="images/icons/info.svg">
</span>
<span>No repositories found.</span>
</div> </div>
</div> </div>


Expand Down
20 changes: 18 additions & 2 deletions src/app/components/app-repositories/app-repositories.component.ts
Expand Up @@ -4,6 +4,10 @@ import { ApiService } from '../../services/api.service';
import { AuthService } from '../../services/auth.service'; import { AuthService } from '../../services/auth.service';
import { SocketService } from '../../services/socket.service'; import { SocketService } from '../../services/socket.service';
import { ConfigService } from '../../services/config.service'; import { ConfigService } from '../../services/config.service';
import { Subject } from 'rxjs/Subject';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
import 'rxjs/add/operator/filter';


export interface Repository { export interface Repository {
url: string; url: string;
Expand All @@ -21,6 +25,8 @@ export class AppRepositoriesComponent implements OnInit {
dropdowns: boolean[]; dropdowns: boolean[];
buildTriggered: boolean; buildTriggered: boolean;
url: string; url: string;
searchKeyword: string;
modelChanged: Subject<string> = new Subject<string>();


constructor( constructor(
private apiService: ApiService, private apiService: ApiService,
Expand All @@ -36,10 +42,16 @@ export class AppRepositoriesComponent implements OnInit {
this.url = this.config.url; this.url = this.config.url;
this.userData = this.authService.getData(); this.userData = this.authService.getData();
this.fetch(); this.fetch();

this.modelChanged
.debounceTime(400)
.distinctUntilChanged()
.subscribe(event => this.fetch(event));
} }


fetch(): void { fetch(keyword = ''): void {
this.apiService.getRepositories(this.userData.id).subscribe(event => { this.loading = true;
this.apiService.getRepositories(this.userData.id, keyword).subscribe(event => {
this.repositories = event.map(repo => { this.repositories = event.map(repo => {
repo.status_badge = this.url + '/api/repositories/badge/' + repo.id; repo.status_badge = this.url + '/api/repositories/badge/' + repo.id;
return repo; return repo;
Expand All @@ -66,4 +78,8 @@ export class AppRepositoriesComponent implements OnInit {
this.buildTriggered = true; this.buildTriggered = true;
setTimeout(() => this.buildTriggered = false, 5000); setTimeout(() => this.buildTriggered = false, 5000);
} }

onKeywordChanged(text: string): void {
this.modelChanged.next(text);
}
} }
3 changes: 2 additions & 1 deletion src/app/services/api.service.ts
Expand Up @@ -24,9 +24,10 @@ export class ApiService {
return this.get(`${this.url}/jobs/${id}`); return this.get(`${this.url}/jobs/${id}`);
} }


getRepositories(userId: string): Observable<any> { getRepositories(userId: string, keyword: string): Observable<any> {
const params = new URLSearchParams(); const params = new URLSearchParams();
params.append('userId', userId); params.append('userId', userId);
params.append('keyword', keyword);
return this.get(`${this.url}/repositories`, params); return this.get(`${this.url}/repositories`, params);
} }


Expand Down
1 change: 1 addition & 0 deletions src/app/styles/colors.sass
Expand Up @@ -4,6 +4,7 @@ $background-button: #273142
$color: #FFFFFF $color: #FFFFFF
$color-secondary: #7F8FA4 $color-secondary: #7F8FA4
$color-disabled: #354052 $color-disabled: #354052
$color-search: #A1A7AF


$border: #313D4F $border: #313D4F
$divider: #364357 $divider: #364357
Expand Down
39 changes: 39 additions & 0 deletions src/app/styles/content.sass
Expand Up @@ -218,3 +218,42 @@
.justify-end .justify-end
display: flex display: flex
justify-content: flex-end justify-content: flex-end

.search-input-container
display: inline-block
position: relative

.search-input
display: block
background: $background
border: 1px solid $divider
border-radius: 4px
min-width: 150px
outline: none
padding: 10px 30px 10px 20px
font-size: 14px
color: $color-search
transition: min-width 300ms ease

&::-webkit-input-placeholder
color: $color-search

&::-moz-placeholer
color: $color-search

&:-ms-input-placeholder
color: $color-search

&:-moz-olaceholder
color: $color-search

&:focus
min-width: 350px

svg
display: block
position: absolute
width: 16px
height: 16px
right: 10px
top: 11px

0 comments on commit 613d1d6

Please sign in to comment.