Skip to content

Instantly share code, notes, and snippets.

@onechiporenko
Last active February 7, 2020 14:51
Show Gist options
  • Save onechiporenko/42f47e96e6de69c0405d441d228307f8 to your computer and use it in GitHub Desktop.
Save onechiporenko/42f47e96e6de69c0405d441d228307f8 to your computer and use it in GitHub Desktop.
Filters with server-side data loading (2.6.1)
import {computed, get} from '@ember/object';
import {isNone} from '@ember/utils';
import DS from 'ember-data';
export default DS.JSONAPIAdapter.extend({
host: 'https://api.github.com',
headers: computed(function () {
const token = ''; //put your token here
const headers = {
Accept: 'application/vnd.github.v3+json,application/vnd.github.symmetra-preview+json,json'
};
if (token) {
headers.Authorization = `token ${token}`;
}
return headers;
}),
handleResponse(status, headers, payload, requestData) {
const linkHeader = headers.Link || headers.link;
const result = this._super(status, headers, payload, requestData);
const links = linkHeader ?linkHeader.split(', ').reduce((memo, link) => {
let [url, rel] = link.split('; ');
try {
[, url] = url.match(/<(.+)>/);
[, rel] = rel.match(/rel=\"(.+)\"/);
} catch(error) {
return;
}
memo[rel] = url;
return memo;
}, {}) : {};
result.links = links;
result.meta = result.meta || {};
let page = 0;
let itemsCount = result.total_count > 1000 ? 1000 : result.total_count;
let pagesCount = 100;
if (links.prev) {
const u = new URL(links.prev);
page = u.searchParams.get('page') + 1;
}
if (links.next) {
const u = new URL(links.next);
page = u.searchParams.get('page') - 1;
}
if (links.last) {
const u = new URL(links.last);
pagesCount = u.searchParams.get('page');
}
result.meta.page = page;
result.meta.itemsCount = itemsCount;
result.meta.pagesCount = Number(pagesCount);
return result;
},
urlForQuery(query, modelName) {
return `${get(this, 'host')}/search/${this.pathForType(modelName)}`;
}
});
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
query(store, type, query) {
query.q = 'ember';
if (query['user.login']) {
query.q += ` user:${query['user.login']}`;
delete query['user.login'];
}
return this._super(...arguments);
}
});
import ApplicationAdapter from './application';
export default ApplicationAdapter.extend({
query(store, type, query) {
query.q = query.search.login;
delete query.search.login;
return this._super(...arguments);
}
});
import Component from '@ember/component';
export default Component.extend({
tagName: '',
instance: null
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Filters with server-side data loading (2.6.1)'
});
import Controller from '@ember/controller';
export default Controller.extend({
columns: [
{
propertyName: 'name',
title: 'Repo Name',
useFilter: false,
useSorting: false
},
{
propertyName: 'fullName',
useFilter: false,
useSorting: false
},
{
propertyName: 'owner.login',
title: 'Owner',
componentForFilterCell: 'related-model-filter',
instanceClassName: 'user',
filteredBy: 'user.login',
searchField: 'login',
dropdownComponent: 'owner-option',
useSorting: false
}
],
filterQueryParameters: {
page: 'page',
pageSize: 'per_page'
}
});
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
name: attr('string'),
fullName: attr('string'),
owner: belongsTo('user')
});
import Model from 'ember-data/model';
import attr from 'ember-data/attr';
import { belongsTo, hasMany } from 'ember-data/relationships';
export default Model.extend({
login: attr('string'),
avatarUrl: attr('string')
});
import Route from '@ember/routing/route';
import {get} from '@ember/object';
export default Route.extend({
model() {
return get(this, 'store').query('repository', {per_page: 10});
}
});
import { isArray } from '@ember/array';
import { pluralize } from 'ember-inflector';
import { decamelize } from '@ember/string';
import DS from 'ember-data';
export default DS.JSONAPISerializer.extend({
keyForAttribute(attr) {
return decamelize(attr);
},
normalizeResponse(store, primaryModelClass, payload, id, requestType) {
const included = [];
payload.data = payload.items.map(item => {
const newItem = {
id: item.id,
type: pluralize(primaryModelClass.modelName),
attributes: item,
relationships: {}
};
primaryModelClass.eachRelationship((attrName, opts) => {
const id = newItem.attributes[attrName].id;
const type = opts.type;
newItem.relationships[attrName] = {data: {id, type}};
included.push({
id,
type,
attributes: newItem.attributes[attrName]
});
});
return newItem;
});
payload.included = included;
return this._super(...arguments);
},
});
.overlay {
position: absolute;
top: 0;
height: 100%;
background: rgba(255,255,255, 0.5);
width: 100%;
}
.overlay p {
display: block;
position: relative;
top: 40%;
text-align: center;
color: #666;
font-size: 40px;
}
.mt {
position: relative;
}
.ember-basic-dropdown {
position: relative; }
.ember-basic-dropdown, .ember-basic-dropdown-content, .ember-basic-dropdown-content * {
box-sizing: border-box; }
.ember-basic-dropdown-content {
position: absolute;
width: auto;
z-index: 1000;
background-color: #ffffff; }
.ember-basic-dropdown-content--left {
left: 0; }
.ember-basic-dropdown-content--right {
right: 0; }
.ember-basic-dropdown-overlay {
position: fixed;
background: rgba(0, 0, 0, 0.5);
width: 100%;
height: 100%;
z-index: 10;
top: 0;
left: 0;
pointer-events: none; }
.ember-basic-dropdown-content-wormhole-origin {
display: inline; }
.ember-power-select-dropdown * {
box-sizing: border-box; }
.ember-power-select-trigger {
position: relative;
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-right: 1px solid #ccc;
border-left: 1px solid #ccc;
border-radius: 4px;
background-color: #ffffff;
line-height: 2;
overflow-x: hidden;
text-overflow: ellipsis;
min-height: 2em;
user-select: none;
-webkit-user-select: none;
color: inherit;
/* Minimum clearfix for modern browsers */ }
.ember-power-select-trigger:after {
content: "";
display: table;
clear: both; }
.ember-power-select-trigger:focus,
.ember-power-select-trigger--active {
border-top: 1px solid #66afe9;
border-bottom: 1px solid #66afe9;
border-right: 1px solid #66afe9;
border-left: 1px solid #66afe9;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
outline: 0; }
.ember-basic-dropdown-trigger--below.ember-power-select-trigger[aria-expanded="true"],
.ember-basic-dropdown-trigger--in-place.ember-power-select-trigger[aria-expanded="true"] {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px; }
.ember-basic-dropdown-trigger--above.ember-power-select-trigger[aria-expanded="true"] {
border-top-left-radius: 4px;
border-top-right-radius: 4px; }
.ember-power-select-placeholder {
color: #999999;
display: block;
overflow-x: hidden;
white-space: nowrap;
text-overflow: ellipsis; }
.ember-power-select-status-icon {
position: absolute;
display: inline-block;
width: 0;
height: 0;
top: 0;
bottom: 0;
margin: auto;
border-style: solid;
border-width: 7px 4px 0 4px;
border-color: #999 transparent transparent transparent; }
.ember-basic-dropdown-trigger[aria-expanded="true"] .ember-power-select-status-icon {
transform: rotate(180deg); }
.ember-power-select-clear-btn {
position: absolute;
cursor: pointer; }
.ember-power-select-trigger-multiple-input {
font-family: inherit;
font-size: inherit;
border: none;
display: inline-block;
line-height: inherit;
-webkit-appearance: none;
outline: none;
padding: 0;
float: left;
background-color: transparent;
text-indent: 2px;
/* There's a browser bug where this selectos cannot be chained with commas */ }
.ember-power-select-trigger-multiple-input:disabled {
background-color: #eeeeee; }
.ember-power-select-trigger-multiple-input::placeholder {
opacity: 1;
color: #999999; }
.ember-power-select-trigger-multiple-input::-webkit-input-placeholder {
opacity: 1;
color: #999999; }
.ember-power-select-trigger-multiple-input::-moz-placeholder {
opacity: 1;
color: #999999; }
.ember-power-select-trigger-multiple-input::-ms-input-placeholder {
opacity: 1;
color: #999999; }
.ember-power-select-multiple-options {
padding: 0;
margin: 0; }
.ember-power-select-multiple-option {
border: 1px solid gray;
border-radius: 4px;
color: #333333;
background-color: #e4e4e4;
padding: 0 4px;
display: inline-block;
line-height: 1.45;
float: left;
margin: 2px 0 2px 3px; }
.ember-power-select-multiple-remove-btn {
cursor: pointer; }
.ember-power-select-multiple-remove-btn:not(:hover) {
opacity: 0.5; }
.ember-power-select-search {
padding: 4px; }
.ember-power-select-search-input {
border: 1px solid #ccc;
border-radius: 3px;
width: 100%;
font-size: inherit;
line-height: inherit;
padding: 0 5px; }
.ember-power-select-search-input:focus {
border: 1px solid #66afe9;
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(102, 175, 233, 0.6);
outline: 0; }
.ember-power-select-dropdown {
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
line-height: 2;
border-radius: 4px;
box-shadow: rgba(0, 0, 0, 0.172549) 0px 6px 12px 0px;
overflow: hidden;
color: inherit; }
.ember-power-select-dropdown.ember-basic-dropdown-content--above {
transform: translateY(calc(-1 * 3px));
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px; }
.ember-power-select-dropdown.ember-basic-dropdown-content--below, .ember-power-select-dropdown.ember-basic-dropdown-content--in-place {
transform: translateY(3px);
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
border-top-left-radius: 4px;
border-top-right-radius: 4px; }
.ember-power-select-dropdown.ember-basic-dropdown-content--in-place {
width: 100%; }
.ember-power-select-options {
list-style: none;
margin: 0;
padding: 0;
user-select: none;
-webkit-user-select: none; }
.ember-power-select-options[role="listbox"] {
overflow-y: auto;
/* in firefox in windows this can cause a word-break issue. Try `overflow-y: scroll` if that happens */
-webkit-overflow-scrolling: touch;
max-height: 14em; }
.ember-power-select-option {
cursor: pointer;
padding: 0 8px; }
.ember-power-select-group[aria-disabled="true"] {
color: #999999;
cursor: not-allowed; }
.ember-power-select-group[aria-disabled="true"] .ember-power-select-option,
.ember-power-select-option[aria-disabled="true"] {
color: #999999;
pointer-events: none;
cursor: not-allowed; }
.ember-power-select-option[aria-selected="true"] {
background-color: #f5f5f5; }
.ember-power-select-option[aria-current="true"] {
background-color: #f5f5f5;
color: inherit; }
.ember-power-select-group-name {
cursor: default;
font-weight: bold; }
.ember-power-select-trigger[aria-disabled=true] {
background-color: #eeeeee; }
.ember-power-select-trigger {
padding: 0 16px 0 0; }
.ember-power-select-selected-item, .ember-power-select-placeholder {
margin-left: 8px; }
.ember-power-select-status-icon {
right: 5px; }
.ember-power-select-clear-btn {
right: 25px; }
.ember-power-select-group .ember-power-select-group .ember-power-select-group-name {
padding-left: 24px; }
.ember-power-select-group .ember-power-select-group .ember-power-select-option {
padding-left: 40px; }
.ember-power-select-group .ember-power-select-option {
padding-left: 24px; }
.ember-power-select-group .ember-power-select-group-name {
padding-left: 8px; }
.ember-power-select-trigger[dir=rtl] {
padding: 0 0 0 16px; }
.ember-power-select-trigger[dir=rtl] .ember-power-select-selected-item, .ember-power-select-trigger[dir=rtl] .ember-power-select-placeholder {
margin-right: 8px; }
.ember-power-select-trigger[dir=rtl] .ember-power-select-multiple-option {
float: right; }
.ember-power-select-trigger[dir=rtl] .ember-power-select-trigger-multiple-input {
float: right; }
.ember-power-select-trigger[dir=rtl] .ember-power-select-status-icon {
left: 5px;
right: initial; }
.ember-power-select-trigger[dir=rtl] .ember-power-select-clear-btn {
left: 25px;
right: initial; }
.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-group .ember-power-select-group-name {
padding-right: 24px; }
.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-group .ember-power-select-option {
padding-right: 40px; }
.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-option {
padding-right: 24px; }
.ember-power-select-dropdown[dir=rtl] .ember-power-select-group .ember-power-select-group-name {
padding-right: 8px; }
<div class="container-fluid">
<h1>{{appName}}</h1>
<p class="alert alert-info">Github repositories with <code>ember</code> keyword are searched.<br>GitHub API won't allow to search more than 1000 items, so <code>total_count</code> is set 1000 if it's greater.</p>
<p>Use your own token (<a href="https://github.com/settings/tokens">settings.tokens</a>) if API-requests limit is reached (set it into the <code>adapters/application.js</code>).</p>
{{outlet}}
</div>
<img style="max-width: 32px; max-height: 32px;" src={{instance.avatarUrl}} alt={{instance.login}}> {{instance.login}}
<p class="alert alert-danger">
{{model.message}}
</p>
{{#models-table-server-paginated
class="mt"
data=model
columns=columns
filterQueryParameters=filterQueryParameters as |mt|}}
{{#if mt.isLoading}}
<div class="overlay">
<p><i class="glyphicon glyphicon-refresh"></i></p>
</div>
{{/if}}
{{mt.table}}
{{mt.footer}}
{{/models-table-server-paginated}}
{
"version": "0.15.0",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js",
"ember": "3.2.2",
"ember-template-compiler": "3.2.2",
"ember-testing": "3.2.2",
"bs3css": "https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css",
"bs3js": "https://stackpath.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
},
"addons": {
"ember-data": "3.2.0",
"ember-models-table": "2.6.1",
"ember-power-select": "2.0.5"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment