Add badge

This commit is contained in:
Stanislav Romanov 2022-05-04 12:54:23 +03:00
parent cab3bf0bdf
commit 915c9932d1
9 changed files with 158 additions and 36 deletions

13
app/components/badge.hbs Normal file
View file

@ -0,0 +1,13 @@
{{#let
'inline-flex items-center px-3 py-0.5 rounded-full text-sm font-medium bg-gray-light text-gray-dark'
(hash
success='bg-green-light text-green-dark'
) as |commonClasses variableClasses|
}}
<span class="{{commonClasses}} {{get variableClasses @style}}" ...attributes>
{{#if @icon}}
<@icon class="mr-1" @size={{16}} />
{{/if}}
{{@label}}
</span>
{{/let}}

View file

@ -1,11 +1,13 @@
import Controller from '@ember/controller'; import Controller from '@ember/controller';
import { action, get, set } from '@ember/object'; import { action, get, set } from '@ember/object';
import arrayEquals from 'meilisearch-admin/utils/array-equals'; import arrayEquals from 'meilisearch-admin/utils/array-equals';
import { ContentSaveOutline } from 'ember-mdi/icons'; import { ContentSaveOutline, Check, CircleMedium } from 'ember-mdi/icons';
export default class AdminIndexesItemSettingsController extends Controller { export default class AdminIndexesItemSettingsController extends Controller {
emptyObj = {}; emptyObj = {};
ContentSaveOutline = ContentSaveOutline; ContentSaveOutline = ContentSaveOutline;
Check = Check;
CircleMedium = CircleMedium;
get rankingRulesFields() { get rankingRulesFields() {
const arr = []; const arr = [];
@ -65,4 +67,17 @@ export default class AdminIndexesItemSettingsController extends Controller {
reorderItems(itemModels) { reorderItems(itemModels) {
set(this.model.settings, 'rankingRules', itemModels); set(this.model.settings, 'rankingRules', itemModels);
} }
@action
setAttributeValue(arr, item) {
if (arr.length === 0 && arr[0] === '*') {
arr = [];
}
if (arr.includes(item)) {
arr = arr.filter((i) => i !== item);
} else {
arr.push(item);
}
}
} }

View file

@ -1,7 +1,13 @@
import query from '../utils/query'; import query from '../utils/query';
import { TrackedArray } from 'tracked-built-ins'; import { TrackedArray } from 'tracked-built-ins';
import { trackedFunction } from 'ember-resources/util/function';
export default class Index { export default class Index {
stats = trackedFunction(this, () => query(`${this.indexPath}/stats`));
displayedAttributes = trackedFunction(this, () =>
query(`${this.indexPath}/settings/displayed-attributes`)
);
constructor(data) { constructor(data) {
for (const key in data) { for (const key in data) {
this[key] = data[key]; this[key] = data[key];
@ -12,6 +18,14 @@ export default class Index {
return `indexes/${this.uid}`; return `indexes/${this.uid}`;
} }
get allAttributesAreDisplayed() {
return (
this.displayedAttributes.value &&
this.displayedAttributes.value.length === 1 &&
this.displayedAttributes.value[0] === '*'
);
}
getSortableAttributes() { getSortableAttributes() {
return query(`${this.indexPath}/settings/sortable-attributes`).then( return query(`${this.indexPath}/settings/sortable-attributes`).then(
(result) => new TrackedArray(result) (result) => new TrackedArray(result)
@ -34,4 +48,10 @@ export default class Index {
body: JSON.stringify(options), body: JSON.stringify(options),
}); });
} }
get fields() {
return this.stats.value
? Object.keys(this.stats.value.fieldDistribution)
: [];
}
} }

View file

@ -37,25 +37,26 @@ class IndexAttribute {
export default class AdminIndexesItemSettingsRoute extends Route { export default class AdminIndexesItemSettingsRoute extends Route {
async model() { async model() {
const index = this.modelFor('admin.indexes.item'); const index = this.modelFor('admin.indexes.item');
const settings = index.getSettings(); // const settings = index.getSettings();
const stats = index.getStats(); const stats = index.stats;
return hash({ index, settings, stats }).then((result) => { return hash({ index, stats });
// Some settings properties may to be ["*"] (all attributes) // .then((result) => {
// this convert it to [attr1, attr2, ...] // // Some settings properties may to be ["*"] (all attributes)
['displayedAttributes', 'searchableAttributes'].forEach((prop) => { // // this convert it to [attr1, attr2, ...]
if ( // ['displayedAttributes', 'searchableAttributes'].forEach((prop) => {
result.settings[prop].length === 1 && // if (
result.settings[prop][0] === '*' // result.settings[prop].length === 1 &&
) { // result.settings[prop][0] === '*'
result.settings[prop] = Object.keys(result.stats.fieldDistribution); // ) {
} // result.settings[prop] = Object.keys(result.stats.fieldDistribution);
}); // }
result.attributes = Object.keys(result.stats.fieldDistribution).map( // });
(name) => new IndexAttribute(name, result.settings) // result.attributes = Object.keys(result.stats.fieldDistribution).map(
); // (name) => new IndexAttribute(name, result.settings)
// );
return result; // return result;
}); // });
} }
} }

View file

@ -1,7 +1,31 @@
{{page-title 'Settings'}} {{page-title 'Settings'}}
<label class="mb-2"> <label class="text-xl mb-2 block">
Attributes Displayed attributes
</label> </label>
<div class="mb-4">
{{#each @model.index.fields as |item|}}
{{#let
(or
@model.index.allAttributesAreDisplayed
(includes item @model.index.displayedAttributes.value)
) as |checked|
}}
<Badge
@label={{item}}
@icon={{if checked this.Check this.CircleMedium}}
@style={{if checked 'success'}}
class="cursor-pointer"
{{on
'click'
(fn
this.setAttributeValue @model.index.displayedAttributes.value item
)
}}
/>
{{/let}}
{{/each}}
</div>
{{!--
<RoyalTable @data={{@model.attributes}} as |Row data|> <RoyalTable @data={{@model.attributes}} as |Row data|>
<Row as |Column|> <Row as |Column|>
<Column @prop="name" /> <Column @prop="name" />
@ -56,7 +80,6 @@
@size="16" @size="16"
class="ml-auto cursor-pointer" class="ml-auto cursor-pointer"
{{on 'click' (fn this.removeRankingRule item)}} {{on 'click' (fn this.removeRankingRule item)}}
{{!-- {{sortable-handle}} --}}
/> />
</div> </div>
{{/each}} {{/each}}
@ -90,4 +113,4 @@
@rejectedText="Error" @rejectedText="Error"
@icon={{this.ContentSaveOutline}} @icon={{this.ContentSaveOutline}}
@onClick={{this.save}} @onClick={{this.save}}
/> /> --}}

View file

@ -1,3 +1,5 @@
const colors = require('tailwindcss/colors');
const light = '#FAFAFA'; const light = '#FAFAFA';
// const gray = '#EEEDEF'; // const gray = '#EEEDEF';
// const dark = '#55585D'; // const dark = '#55585D';
@ -18,10 +20,21 @@ module.exports = {
extend: { extend: {
colors: { colors: {
light, light,
gray, // gray,
dark, dark,
text, text,
primary, primary,
gray: {
light: colors.gray['100'],
DEFAULT: colors.gray['500'],
dark: colors.gray['800'],
},
green: {
light: colors.emerald['100'],
DEFAULT: colors.emerald['500'],
dark: colors.emerald['800'],
},
}, },
}, },
// borderColor: gray, // borderColor: gray,

33
package-lock.json generated
View file

@ -56,7 +56,7 @@
"ember-power-select": "^5.0.4", "ember-power-select": "^5.0.4",
"ember-qunit": "^5.1.5", "ember-qunit": "^5.1.5",
"ember-resolver": "^8.0.3", "ember-resolver": "^8.0.3",
"ember-resources": "^4.4.0", "ember-resources": "^4.7.1",
"ember-set-helper": "^2.0.1", "ember-set-helper": "^2.0.1",
"ember-sortable": "^3.0.1", "ember-sortable": "^3.0.1",
"ember-source": "~4.2.0", "ember-source": "~4.2.0",
@ -16453,17 +16453,28 @@
} }
}, },
"node_modules/ember-resources": { "node_modules/ember-resources": {
"version": "4.4.0", "version": "4.7.1",
"resolved": "https://registry.npmjs.org/ember-resources/-/ember-resources-4.4.0.tgz", "resolved": "https://registry.npmjs.org/ember-resources/-/ember-resources-4.7.1.tgz",
"integrity": "sha512-bMk3qdD7sgG33VY3Znri6z2p/XneITuT02zgFROS9flvUE124rnW/m9ND/fySt5EOE8URhS3IZ6MImIgI1dyCg==", "integrity": "sha512-5qU9yKXbwOnGaEpJFW+v/NFjXQHLjX8otQGWl9DWvW7qKLICcaDQyNeCiFl06qux3Zfnf2RqVl9Hz8DM0Q9xGw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@ember/test-waiters": "^3.0.0", "@babel/runtime": "^7.17.8",
"@embroider/addon-shim": "^1.2.0", "@embroider/addon-shim": "^1.2.0",
"@embroider/macros": "^1.2.0" "@embroider/macros": "^1.2.0"
}, },
"engines": { "peerDependencies": {
"node": ">=12.2.0 < 13 || >= 14" "@ember/test-waiters": "^3.0.0",
"@glimmer/tracking": "^1.0.0",
"ember-concurrency": "^1.0.0 || ^2.0.0",
"ember-source": ">= 3.25.0"
},
"peerDependenciesMeta": {
"@ember/test-waiters": {
"optional": true
},
"ember-concurrency": {
"optional": true
}
} }
}, },
"node_modules/ember-rfc176-data": { "node_modules/ember-rfc176-data": {
@ -43005,12 +43016,12 @@
} }
}, },
"ember-resources": { "ember-resources": {
"version": "4.4.0", "version": "4.7.1",
"resolved": "https://registry.npmjs.org/ember-resources/-/ember-resources-4.4.0.tgz", "resolved": "https://registry.npmjs.org/ember-resources/-/ember-resources-4.7.1.tgz",
"integrity": "sha512-bMk3qdD7sgG33VY3Znri6z2p/XneITuT02zgFROS9flvUE124rnW/m9ND/fySt5EOE8URhS3IZ6MImIgI1dyCg==", "integrity": "sha512-5qU9yKXbwOnGaEpJFW+v/NFjXQHLjX8otQGWl9DWvW7qKLICcaDQyNeCiFl06qux3Zfnf2RqVl9Hz8DM0Q9xGw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@ember/test-waiters": "^3.0.0", "@babel/runtime": "^7.17.8",
"@embroider/addon-shim": "^1.2.0", "@embroider/addon-shim": "^1.2.0",
"@embroider/macros": "^1.2.0" "@embroider/macros": "^1.2.0"
} }

View file

@ -76,7 +76,7 @@
"ember-power-select": "^5.0.4", "ember-power-select": "^5.0.4",
"ember-qunit": "^5.1.5", "ember-qunit": "^5.1.5",
"ember-resolver": "^8.0.3", "ember-resolver": "^8.0.3",
"ember-resources": "^4.4.0", "ember-resources": "^4.7.1",
"ember-set-helper": "^2.0.1", "ember-set-helper": "^2.0.1",
"ember-sortable": "^3.0.1", "ember-sortable": "^3.0.1",
"ember-source": "~4.2.0", "ember-source": "~4.2.0",

View file

@ -0,0 +1,26 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
module('Integration | Component | badge', function (hooks) {
setupRenderingTest(hooks);
test('it renders', async function (assert) {
// Set any properties with this.set('myProperty', 'value');
// Handle any actions with this.set('myAction', function(val) { ... });
await render(hbs`<Badge />`);
assert.dom(this.element).hasText('');
// Template block usage:
await render(hbs`
<Badge>
template block text
</Badge>
`);
assert.dom(this.element).hasText('template block text');
});
});