mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-02 11:49:23 +00:00
Refractor Search to TS (#1373)
This commit is contained in:
parent
141ae826bc
commit
ca7110ea11
@ -1,75 +1,9 @@
|
||||
import Controller from '@ember/controller';
|
||||
import { computed, set, get } from '@ember/object';
|
||||
import { capitalize } from '@ember/string';
|
||||
import { action } from '@ember-decorators/object';
|
||||
import { set } from '@ember/object';
|
||||
import { action, computed } from '@ember-decorators/object';
|
||||
|
||||
// gradual refactor into es class, hence extends EmberObject instance
|
||||
export default class Search extends Controller.extend({
|
||||
isMetrics: computed('model.category', function() {
|
||||
var model = this.get('model');
|
||||
if (model && model.category) {
|
||||
if (model.category.toLocaleLowerCase() === 'metrics') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}),
|
||||
|
||||
previousPage: computed('model.page', function() {
|
||||
var model = this.get('model');
|
||||
if (model && model.page) {
|
||||
var currentPage = model.page;
|
||||
if (currentPage <= 1) {
|
||||
return currentPage;
|
||||
} else {
|
||||
return currentPage - 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}),
|
||||
nextPage: computed('model.page', function() {
|
||||
var model = this.get('model');
|
||||
if (model && model.page) {
|
||||
var currentPage = model.page;
|
||||
var totalPages = model.totalPages;
|
||||
if (currentPage >= totalPages) {
|
||||
return totalPages;
|
||||
} else {
|
||||
return currentPage + 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}),
|
||||
first: computed('model.page', function() {
|
||||
var model = this.get('model');
|
||||
if (model && model.page) {
|
||||
var currentPage = model.page;
|
||||
if (currentPage <= 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
last: computed('model.page', function() {
|
||||
var model = this.get('model');
|
||||
if (model && model.page) {
|
||||
var currentPage = model.page;
|
||||
var totalPages = model.totalPages;
|
||||
if (currentPage >= totalPages) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
})
|
||||
}) {
|
||||
export default class SearchController extends Controller {
|
||||
queryParams = ['keyword', 'category', 'source', 'page'];
|
||||
|
||||
/**
|
||||
@ -107,7 +41,80 @@ export default class Search extends Controller.extend({
|
||||
* @param source
|
||||
*/
|
||||
@action
|
||||
sourceDidChange(source) {
|
||||
sourceDidChange(source: string) {
|
||||
set(this, 'source', source);
|
||||
}
|
||||
|
||||
@computed('model.category')
|
||||
get isMetrics(): boolean {
|
||||
const model = this.get('model');
|
||||
if (model && model.category) {
|
||||
if (model.category.toLocaleLowerCase() === 'metrics') {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@computed('model.page')
|
||||
get previousPage(): number {
|
||||
const model = this.get('model');
|
||||
if (model && model.page) {
|
||||
var currentPage = model.page;
|
||||
if (currentPage <= 1) {
|
||||
return currentPage;
|
||||
} else {
|
||||
return currentPage - 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@computed('model.page')
|
||||
get nextPage(): number {
|
||||
const model = this.get('model');
|
||||
if (model && model.page) {
|
||||
const currentPage = model.page;
|
||||
const totalPages = model.totalPages;
|
||||
if (currentPage >= totalPages) {
|
||||
return totalPages;
|
||||
} else {
|
||||
return currentPage + 1;
|
||||
}
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@computed('model.page')
|
||||
get first(): boolean {
|
||||
const model = this.get('model');
|
||||
if (model && model.page) {
|
||||
const currentPage = model.page;
|
||||
if (currentPage <= 1) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@computed('model.page')
|
||||
get last(): boolean {
|
||||
const model = this.get('model');
|
||||
if (model && model.page) {
|
||||
const currentPage = model.page;
|
||||
const totalPages = model.totalPages;
|
||||
if (currentPage >= totalPages) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import { isBlank } from '@ember/utils';
|
||||
import $ from 'jquery';
|
||||
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
||||
import buildUrl from 'wherehows-web/utils/build-url';
|
||||
import createSearchEntries from 'wherehows-web/utils/datasets/create-search-entries';
|
||||
|
||||
const queryParams = ['keyword', 'category', 'page', 'source'];
|
||||
// TODO: DSS-6581 Create URL retrieval module
|
||||
const urlRoot = '/api/v1/search';
|
||||
|
||||
export default Route.extend(AuthenticatedRouteMixin, {
|
||||
// Set `refreshModel` for each queryParam to true
|
||||
// so each url state change results in a full transition
|
||||
queryParams: queryParams.reduce((queryParams, param) => {
|
||||
queryParams[param] = { refreshModel: true };
|
||||
return queryParams;
|
||||
}, {}),
|
||||
|
||||
/**
|
||||
* Applies the returned results object as the route model and sets
|
||||
* keyword property on the route controller
|
||||
* @param {Object} controller search route controller
|
||||
* @param {Object} model search results
|
||||
*/
|
||||
setupController(controller, model) {
|
||||
const { keywords } = model;
|
||||
|
||||
controller.setProperties({
|
||||
model,
|
||||
keyword: keywords
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
*/
|
||||
model(params = {}) {
|
||||
const searchUrl = queryParams.reduce((url, queryParam) => {
|
||||
const queryValue = params[queryParam];
|
||||
if (!isBlank(queryValue)) {
|
||||
return buildUrl(url, queryParam, queryValue);
|
||||
}
|
||||
|
||||
return url;
|
||||
}, urlRoot);
|
||||
|
||||
return Promise.resolve($.getJSON(searchUrl)).then(({ status, result }) => {
|
||||
if (status === 'ok') {
|
||||
const { keywords, data } = result;
|
||||
|
||||
createSearchEntries(data, keywords);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return Promise.reject(new Error(`Request for ${searchUrl} failed with: ${status}`));
|
||||
});
|
||||
}
|
||||
});
|
||||
37
wherehows-web/app/routes/search.ts
Normal file
37
wherehows-web/app/routes/search.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import Route from '@ember/routing/route';
|
||||
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
|
||||
import createSearchEntries from 'wherehows-web/utils/datasets/create-search-entries';
|
||||
import { refreshModelQueryParams } from 'wherehows-web/utils/helpers/routes';
|
||||
import SearchController from 'wherehows-web/controllers/search';
|
||||
import { readSearch, ISearchApiParams } from 'wherehows-web/utils/api/search';
|
||||
|
||||
export default class SearchRoute extends Route.extend(AuthenticatedRouteMixin) {
|
||||
// Set `refreshModel` for each queryParam to true
|
||||
// so each url state change results in a full transition
|
||||
queryParams = refreshModelQueryParams(['keyword', 'category', 'page', 'source']);
|
||||
|
||||
/**
|
||||
* Applies the returned results object as the route model and sets
|
||||
* keyword property on the route controller
|
||||
* @param {Object} controller search route controller
|
||||
* @param {Object} model search results
|
||||
*/
|
||||
setupController(controller: SearchController, model: any) {
|
||||
const { keywords } = model;
|
||||
|
||||
controller.setProperties({
|
||||
model,
|
||||
keyword: keywords
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an API call and process search entries
|
||||
*/
|
||||
async model(apiParams: ISearchApiParams) {
|
||||
const { result } = await readSearch(apiParams);
|
||||
const { keywords, data } = result;
|
||||
createSearchEntries(data, keywords);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
23
wherehows-web/app/utils/api/search.ts
Normal file
23
wherehows-web/app/utils/api/search.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { getApiRoot, ApiStatus } from 'wherehows-web/utils/api/shared';
|
||||
import buildUrl from 'wherehows-web/utils/build-url';
|
||||
import { getJSON } from 'wherehows-web/utils/api/fetcher';
|
||||
|
||||
export interface ISearchApiParams {
|
||||
keyword: string;
|
||||
category: string;
|
||||
source: string;
|
||||
page: number;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface ISearchResponse {
|
||||
status: ApiStatus;
|
||||
result: {
|
||||
keywords: string;
|
||||
data: Array<any>;
|
||||
};
|
||||
}
|
||||
|
||||
export const searchUrl = (params: ISearchApiParams): string => buildUrl(`${getApiRoot()}/search`, params);
|
||||
|
||||
export const readSearch = (params: ISearchApiParams) => getJSON<ISearchResponse>({ url: searchUrl(params) });
|
||||
@ -1,4 +1,5 @@
|
||||
import { encode, decode } from 'wherehows-web/utils/encode-decode-uri-component-with-space';
|
||||
import { isBlank } from '@ember/utils';
|
||||
|
||||
/**
|
||||
* Construct a url by appending a query pair (?key=value | &key=value) to a base url and
|
||||
@ -8,34 +9,56 @@ import { encode, decode } from 'wherehows-web/utils/encode-decode-uri-component-
|
||||
* @param {String} queryValue
|
||||
* @returns {string}
|
||||
*/
|
||||
export default (baseUrl: string, queryParam: string, queryValue: string): string => {
|
||||
function buildUrl(): string;
|
||||
function buildUrl(baseUrl: string, mapParams: Record<string, any>): string;
|
||||
function buildUrl(baseUrl: string, queryKey: string, queryValue: string): string;
|
||||
function buildUrl(baseUrl?: string, queryParamOrMap?: string | Record<string, string>, queryValue?: string): string {
|
||||
if (!baseUrl) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!queryParam) {
|
||||
if (!queryParamOrMap) {
|
||||
return baseUrl;
|
||||
}
|
||||
// If the query string already contains the initial question mark append
|
||||
// kv-pair with ampersand
|
||||
const separator = String(baseUrl).includes('?') ? '&' : '?';
|
||||
|
||||
// Malformed URL will cause decodeURIComponent to throw
|
||||
// handle and encode queryValue in such instance
|
||||
try {
|
||||
// Check if queryValue is already encoded,
|
||||
// otherwise encode queryValue before composing url
|
||||
// e.g. if user directly enters query in location bar
|
||||
if (decode(queryValue) === queryValue) {
|
||||
queryValue = encode(queryValue);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof URIError) {
|
||||
queryValue = encode(queryValue);
|
||||
}
|
||||
|
||||
throw err;
|
||||
let paramMap: { [x: string]: string };
|
||||
if (typeof queryParamOrMap === 'string') {
|
||||
paramMap = {
|
||||
[queryParamOrMap]: queryValue || ''
|
||||
};
|
||||
} else {
|
||||
paramMap = queryParamOrMap;
|
||||
}
|
||||
|
||||
return `${baseUrl}${separator}${queryParam}=${queryValue}`;
|
||||
};
|
||||
return Object.keys(paramMap).reduce((url, paramKey) => {
|
||||
// If the query string already contains the initial question mark append
|
||||
// kv-pair with ampersand
|
||||
const separator = String(url).includes('?') ? '&' : '?';
|
||||
let paramValue = paramMap[paramKey];
|
||||
|
||||
if (isBlank(paramValue)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
// Malformed URL will cause decodeURIComponent to throw
|
||||
// handle and encode queryValue in such instance
|
||||
try {
|
||||
// Check if queryValue is already encoded,
|
||||
// otherwise encode queryValue before composing url
|
||||
// e.g. if user directly enters query in location bar
|
||||
if (decode(paramValue) === queryValue) {
|
||||
paramValue = encode(paramValue);
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof URIError) {
|
||||
paramValue = encode(paramValue);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
return `${url}${separator}${paramKey}=${paramValue}`;
|
||||
}, baseUrl);
|
||||
}
|
||||
|
||||
export default buildUrl;
|
||||
|
||||
@ -8,7 +8,7 @@ module('Unit | Utility | build url', function() {
|
||||
let result = buildUrl();
|
||||
assert.equal(result, '', 'returns an empty string when no arguments are passed');
|
||||
|
||||
result = buildUrl(baseUrl, '');
|
||||
result = buildUrl(baseUrl, '', '');
|
||||
assert.equal(result, baseUrl, 'returns the baseUrl when no query parameter is supplied');
|
||||
|
||||
result = buildUrl(baseUrl, 'search', 'text');
|
||||
@ -16,5 +16,21 @@ module('Unit | Utility | build url', function() {
|
||||
|
||||
result = buildUrl(result, 'query', 'text2');
|
||||
assert.equal(result, `${baseUrl}?search=text&query=text2`);
|
||||
|
||||
result = buildUrl(baseUrl, {
|
||||
keyName1: 'keyValue1',
|
||||
keyName2: 2,
|
||||
keyName3: true
|
||||
});
|
||||
assert.equal(result, `${baseUrl}?keyName1=keyValue1&keyName2=2&keyName3=true`);
|
||||
|
||||
result = buildUrl(baseUrl, {
|
||||
keyName1: 0,
|
||||
keyName3: undefined,
|
||||
keyName4: '',
|
||||
keyName5: null,
|
||||
keyName2: false
|
||||
});
|
||||
assert.equal(result, `${baseUrl}?keyName1=0&keyName2=false`);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user