PR#72 [DO NOT MERGE] Package search

Proposed 14 days ago by amitosh
Modified 2 days ago
From forks/amitosh/Fedora-app package-search  into Fedora-app master

None

file changed

@@ -7,6 +7,7 @@ 

  import { SocialPage } from '../pages/social/social';

  import { WomenPage } from '../pages/women/women';

  import { FirstPage } from '../pages/first/first';

+ import { PackageSearchPage } from '../pages/package-search/package-search';

  import { SplashScreen } from '@ionic-native/splash-screen';

  

  /**

@@ -33,7 +34,8 @@

        { title: 'Social', component: SocialPage },

        { title: 'Ask', component: AskPage },

        { title: 'Calendar', component: CalendarPage },

-       { title: 'Women', component: WomenPage }

+       { title: 'Women', component: WomenPage },

+       { title: 'Package Search', component: PackageSearchPage }

  

      ];

  
file changed

@@ -17,8 +17,11 @@ 

  import { CalendarPage } from '../pages/calendar/calendar';

  import { SocialPage } from '../pages/social/social';

  import { WomenPage } from '../pages/women/women';

+ import { PackageSearchPage } from '../pages/package-search/package-search';

+ import { ViewPackagePage } from '../pages/view-package/view-package';

  

  import { Browser } from '../providers/browser/browser';

+ import { PackageSearchProvider } from '../providers/package-search/package-search';

  

  @NgModule({

    declarations: [

@@ -28,7 +31,9 @@

      AskPage,

      CalendarPage,

      SocialPage,

-     WomenPage

+     WomenPage,

+     PackageSearchPage,

+     ViewPackagePage

    ],

    imports: [

      BrowserModule,

@@ -44,7 +49,9 @@

      AskPage,

      CalendarPage,

      SocialPage,

-     WomenPage

+     WomenPage,

+     PackageSearchPage,

+     ViewPackagePage

    ],

    providers: [

      Browser,
file changed

@@ -1,6 +1,4 @@ 

  // http://ionicframework.com/docs/v2/theming/

- 

- 

  // App Global Sass

  // --------------------------------------------------

  // Put style rules here that you want to apply globally. These

@@ -15,18 +13,33 @@

  // for the .md, .ios, or .wp mode classes. The mode class is

  // automatically applied to the <body> element in the app.

  // http://ionicframework.com/docs/v2/theming/

- 

  // @import "../pages/magazine/magazine";

  // @import "../pages/ask/ask";

  // @import "../pages/calendar/calendar";

  // @import "../pages/social/social";

  // @import "../pages/women/women";

  // @import "../pages/first/first";

+ // App Shared Rules

+ .iframeWrapper iframe {

+     width: 100%;

+     height: 100%;

+ }

  

+ [padding] ion-list ion-item {

+     h1:first-child,

+     h2:first-child,

+     h3:first-child,

+     h4:first-child,

+     h5:first-child,

+     h6:first-child {

+         margin-top: unset;

+     }

+ }

  

- // App Shared Rules

+ .pkg-lib {

+   color: #03A9F4

+ }

  

- .iframeWrapper iframe {

-   width: 100%;

-   height: 100%;

+ .pkg-devel {

+   color: #FFEB3B;

  }

@@ -0,0 +1,28 @@ 

+ <!--

+   Generated template for the SearchPage page.

+ 

+   See http://ionicframework.com/docs/components/#navigation for more info on

+   Ionic pages and navigation.

+ -->

+ <ion-header>

+ 

+   <ion-navbar>

+     <ion-title>Fedora Package Search</ion-title>

+   </ion-navbar>

+ 

+ </ion-header>

+ 

+ 

+ <ion-content padding>

+   <ion-searchbar [(ngModel)]="searchQuery" (cancel)="clear()" (change)="search()" autocorrect="off"></ion-searchbar>

+   <ion-list>

+     <ion-list-header *ngIf="packages.length > 0">

+         Showing {{ matches }} results

+       </ion-list-header>

+     <ion-item (click)="showPackage(pkg)" *ngFor="let pkg of packages">

+       <ion-icon [ngClass]="getPackageType(pkg)" name="cube" item-start></ion-icon>

+       <h2>{{ pkg.name }}</h2>

+       <h3>{{ pkg.summary }}</h3>

+     </ion-item>

+   </ion-list>

+ </ion-content>

@@ -0,0 +1,3 @@ 

+ page-search {

+ 

+ }

@@ -0,0 +1,46 @@ 

+ import { Component } from '@angular/core';

+ import { NavController } from 'ionic-angular';

+ import { PackageSearchProvider, Package } from '../../providers/package-search/package-search';

+ import { ViewPackagePage } from '../view-package/view-package';

+ import { getPackageType } from '../../utils';

+ 

+ const RESULTS_PER_PAGE = 10;

+ 

+ @Component({

+   templateUrl: 'package-search.html',

+   providers: [PackageSearchProvider]

+ })

+ export class PackageSearchPage {

+ 

+   private searchQuery:string;

+   private offset = 0;

+   private pageSize = RESULTS_PER_PAGE;

+   private matches = 0;

+   private packages:Package[] = [];

+ 

+   constructor(public navCtrl: NavController, private searchProvider:PackageSearchProvider) {

+   }

+ 

+   search() {

+     this.searchProvider.search(this.searchQuery, RESULTS_PER_PAGE, this.offset)

+       .subscribe( r => {

+         this.packages = r.packages;

+         this.offset = r.offset;

+         this.matches = r.matches;

+       });

+   }

+ 

+   clear() {

+     this.packages = [];

+     this.offset = 0;

+     this.matches = 0;

+   }

+ 

+   showPackage(pkg:Package) {

+     this.navCtrl.push(ViewPackagePage, { pkg });

+   }

+ 

+   getPackageType(pkg:Package) {

+     return getPackageType(pkg.name);

+   }

+ }

@@ -0,0 +1,36 @@ 

+ <!--

+   Generated template for the ViewPackagePage page.

+ 

+   See http://ionicframework.com/docs/components/#navigation for more info on

+   Ionic pages and navigation.

+ -->

+ <ion-header>

+ 

+   <ion-navbar>

+     <ion-title>Package {{ pkg.name }}</ion-title>

+   </ion-navbar>

+ 

+ </ion-header>

+ 

+ 

+ <ion-content padding>

+   <h1>{{ pkg.name }}</h1>

+   <p>{{ pkg.summary }}</p>

+   <p *ngIf="pkg.upstreamUrl">

+     <a href="{{ pkg.upstreamUrl }}">{{ pkg.upstreamUrl }}</a>

+   </p>

+   <h3>Description</h3>

+   <p>{{ pkg.description }}</p>

+   <h3>Install</h3>

+   <p class="code-block" padding>

+     <code>$ <span>sudo dnf install {{ pkg.name }}</span></code>

+   </p>

+   <h3 *ngIf="pkg.subPackages.length > 0">Sub packages</h3>

+   <ion-list *ngIf="pkg.subPackages.length > 0">

+     <ion-item (click)="showPackage(pkg)" *ngFor="let pkg of pkg.subPackages">

+       <ion-icon [ngClass]="getPackageType(pkg)" name="cube" item-start></ion-icon>

+       <h2>{{ pkg.name }}</h2>

+       <h3>{{ pkg.summary }}</h3>

+     </ion-item>

+   </ion-list>

+ </ion-content>

@@ -0,0 +1,6 @@ 

+ page-view-package {

+   .code-block {

+     background: #f0f0f0;

+     border-radius: 3px;

+   }

+ }

@@ -0,0 +1,32 @@ 

+ import { Component } from '@angular/core';

+ import { NavController, NavParams } from 'ionic-angular';

+ import { Package } from 'providers/package-search/package-search';

+ import { getPackageType } from '../../utils';

+ 

+ /**

+  * Generated class for the ViewPackagePage page.

+  *

+  * See https://ionicframework.com/docs/components/#navigation for more info on

+  * Ionic pages and navigation.

+  */

+ 

+ @Component({

+   selector: 'page-view-package',

+   templateUrl: 'view-package.html',

+ })

+ export class ViewPackagePage {

+ 

+   private pkg: Package;

+ 

+   constructor(public navCtrl: NavController, public navParams: NavParams) {

+     this.pkg = this.navParams.get('pkg') || {};

+   }

+ 

+   showPackage(pkg: Package) {

+     this.navCtrl.push(ViewPackagePage, { pkg });

+   }

+ 

+   getPackageType(pkg:Package) {

+     return getPackageType(pkg.name);

+   }

+ }

@@ -0,0 +1,62 @@ 

+ import { HttpClient } from '@angular/common/http';

+ import { Injectable } from '@angular/core';

+ import { Observable } from 'rxjs/Observable';

+ 

+ const API_ENDPOINT = 'https://apps.fedoraproject.org/packages/fcomm_connector/xapian/query/search_packages/';

+ 

+ export interface SearchResult {

+   matches: number,

+   count: number,

+   offset: number,

+   pageSize: number,

+   packages: Package[]

+ }

+ 

+ export interface Package {

+   name: string,

+   summary: string,

+   upstreamUrl: string,

+   description: string,

+   branch: string,

+   develOwner: string,

+   subPackages: Package[]

+ }

+ 

+ function mapPackage(pkg: any): Package {

+   return {

+     name: pkg.name,

+     summary: pkg.summary,

+     upstreamUrl: pkg.upstream_url,

+     description: pkg.description,

+     branch: pkg.branch,

+     develOwner: pkg.devel_owner,

+     subPackages: pkg.sub_pkgs ? pkg.sub_pkgs.map(mapPackage) : false

+   };

+ }

+ 

+ @Injectable()

+ export class PackageSearchProvider {

+ 

+   constructor(private http: HttpClient) {

+   }

+ 

+   public search(query: string, limit = 10, offset = 0): Observable<SearchResult> {

+     const queryObjectStr = JSON.stringify({

+       filters: {

+         search: query

+       },

+       rows_per_page: limit,

+       start_row: offset

+     });

+ 

+     return this.http.get(`${API_ENDPOINT}/${queryObjectStr}`)

+       .map((res: any) => ({

+         matches: res.total_rows,

+         count: res.visible_rows,

+         offset: res.start_row,

+         pageSize: res.rows_per_page,

+         packages: res.rows.map(mapPackage)

+       }));

+   }

+ 

+ }
src/utils.ts +24 -0
file changed

@@ -19,3 +19,27 @@ 

  export function defaultValue<T>(value:T): OperatorFunction<T, T> {

    return map<T,T>((x:T) => x ? x : value );

  }

+ 

+ /**

+  * Return the type of package from it names.

+  *

+  * Matches the name against the Fedora packaging guidelines

+  * Taken from: https://fedoraproject.org/wiki/Packaging:Naming?rd=Packaging:NamingGuidelines

+  * @param pkgName package name

+  */

+ export function getPackageType(pkgName:string) {

+   if (pkgName.endsWith('-devel')) {

+     return 'pkg-devel';

+   } else if (pkgName.endsWith('-libs')) {

+     return 'pkg-lib';

+   } else if(pkgName.endsWith('-doc')) {

+     return 'pkg-doc';

+   } else if(/^\w*-langpack(-[a-zA-Z]{2})?$/.test(pkgName)) {

+     return 'pkg-langpack';

+   } else if(pkgName.endsWith('-fonts')) {

+     return 'pkg-font';

+   }

+ 

+   return '';

+ }

+ 
14 days ago

rebased onto 7913e30