Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Permettre de filtrer sur les category des Profil Cible sur PixAdmin(PIX-14651) #10263

Open
wants to merge 7 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 74 additions & 30 deletions admin/app/components/target-profiles/list-summary-items.gjs
Original file line number Diff line number Diff line change
@@ -1,61 +1,105 @@
import PixFilterBanner from '@1024pix/pix-ui/components/pix-filter-banner';
import PixInput from '@1024pix/pix-ui/components/pix-input';
import PixMultiSelect from '@1024pix/pix-ui/components/pix-multi-select';
import PixPagination from '@1024pix/pix-ui/components/pix-pagination';
import { fn } from '@ember/helper';
import { action } from '@ember/object';
import { LinkTo } from '@ember/routing';
import { service } from '@ember/service';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { t } from 'ember-intl';

import formatDate from '../../helpers/format-date';
import { categories } from '../../helpers/target-profile-categories.js';

export default class TargetProfileListSummaryItems extends Component {
searchedId = this.args.id;
searchedName = this.args.name;
@service intl;
@tracked selectedValues = [];

get isClearFiltersButtonDisabled() {
return !this.args.id && !this.args.name && !this.args.categories;
}

get categoryOptions() {
const categTest = Object.entries(categories).map(([key, value]) => ({ label: this.intl.t(value), value: key }));
return categTest;
}

@action
triggerCategoriesFiltering(values) {
this.args.triggerFiltering('categories', { target: { value: values } });
}

<template>
<PixFilterBanner
class="page-body-template__content"
@title={{t "common.filters.title"}}
aria-label={{t "pages.target-profiles.filters.aria-label"}}
@details={{t "pages.target-profiles.filters.count" [email protected]}}
@clearFiltersLabel={{t "common.filters.actions.clear"}}
@onClearFilters={{@onResetFilter}}
@isClearFilterButtonDisabled={{this.isClearFiltersButtonDisabled}}
>
<PixInput
type="text"
value={{@id}}
oninput={{fn @triggerFiltering "id"}}
placeholder={{t "pages.target-profiles.filters.search-by-id.placeholder"}}
@screenReaderOnly={{true}}
>
<:label>{{t "pages.target-profiles.filters.search-by-id.name"}}</:label>
</PixInput>

<PixInput
type="text"
value={{@name}}
placeholder={{t "pages.target-profiles.filters.search-by-name.placeholder"}}
oninput={{fn @triggerFiltering "name"}}
@screenReaderOnly={{true}}
>
<:label>{{t "pages.target-profiles.filters.search-by-name.name"}}</:label>
</PixInput>
<PixMultiSelect
@id="categories"
@screenReaderOnly={{true}}
@placeholder={{t "common.filters.target-profile.placeholder"}}
@onChange={{this.triggerCategoriesFiltering}}
@values={{@categories}}
@options={{this.categoryOptions}}
>
<:label>{{t "common.filters.target-profile.label"}}</:label>
<:default as |option|>{{option.label}}</:default>
</PixMultiSelect>

</PixFilterBanner>

<div class="content-text content-text--small">
<div class="table-admin">
<table>

<thead>
<tr>
<th class="table__column table__column--id" id="target-profile-id">ID</th>
<th id="target-profile-name">Nom</th>
<th class="col-date">Date de création</th>
<th class="col-status" id="target-profile-status">Statut</th>
</tr>
<tr>
<td class="table__column table__column--id">
<PixInput
type="text"
value={{this.searchedId}}
oninput={{fn @triggerFiltering "id"}}
aria-label="Filtrer les profils cible par un id"
/>
</td>
<td>
<PixInput
type="text"
value={{this.searchedName}}
oninput={{fn @triggerFiltering "name"}}
aria-label="Filtrer les profils cible par un nom"
/>
</td>
<td></td>
<td></td>
<th class="table__column table__column--id">{{t "common.fields.id"}}</th>
<th>{{t "common.fields.name"}}</th>
<th>{{t "common.fields.target-profile.category.name"}}</th>
<th class="col-date">{{t "common.fields.createdAt"}}</th>
<th class="col-status">{{t "common.fields.status"}}</th>
</tr>
</thead>

{{#if @summaries}}
<tbody>
{{#each @summaries as |summary|}}
<tr aria-label="Profil cible">
<td headers="target-profile-id" class="table__column table__column--id">{{summary.id}}</td>
<td headers="target-profile-name">
<td class="table__column table__column--id">{{summary.id}}</td>
<td>
<LinkTo @route="authenticated.target-profiles.target-profile" @model={{summary.id}}>
{{summary.name}}
</LinkTo>
</td>
<td class="table__column table__column--id">{{t summary.translationKeyCategory}}</td>
<td class="table__column">{{formatDate summary.createdAt}}</td>
<td headers="target-profile-status" class="target-profile-table-column__status">
<td class="target-profile-table-column__status">
{{if summary.outdated "Obsolète" "Actif"}}
</td>
</tr>
Expand Down
10 changes: 9 additions & 1 deletion admin/app/controllers/authenticated/target-profiles/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ import config from 'pix-admin/config/environment';
const DEFAULT_PAGE_NUMBER = 1;

export default class ListController extends Controller {
queryParams = ['pageNumber', 'pageSize', 'id', 'name'];
queryParams = ['pageNumber', 'pageSize', 'id', 'name', 'categories'];
DEBOUNCE_MS = config.pagination.debounce;

@tracked pageNumber = DEFAULT_PAGE_NUMBER;
@tracked pageSize = 10;
@tracked id = null;
@tracked name = null;
@tracked categories = [];

updateFilters(filters) {
for (const filterKey of Object.keys(filters)) {
Expand All @@ -26,4 +27,11 @@ export default class ListController extends Controller {
triggerFiltering(fieldName, event) {
debounceTask(this, 'updateFilters', { [fieldName]: event.target.value }, this.DEBOUNCE_MS);
}

@action
onResetFilter() {
this.id = null;
this.name = null;
this.categories = [];
}
}
11 changes: 11 additions & 0 deletions admin/app/helpers/target-profile-categories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const categories = {
OTHER: 'common.fields.target-profile.category.tags.OTHER',
DISCIPLINE: 'common.fields.target-profile.category.tags.DISCIPLINE',
COMPETENCES: 'common.fields.target-profile.category.tags.COMPETENCES',
PREDEFINED: 'common.fields.target-profile.category.tags.PREDEFINED',
CUSTOM: 'common.fields.target-profile.category.tags.CUSTOM',
PIX_PLUS: 'common.fields.target-profile.category.tags.PIX_PLUS',
SUBJECT: 'common.fields.target-profile.category.tags.SUBJECT',
TARGETED: 'common.fields.target-profile.category.tags.TARGETED',
BACK_TO_SCHOOL: 'common.fields.target-profile.category.tags.BACK_TO_SCHOOL',
};
6 changes: 6 additions & 0 deletions admin/app/models/target-profile-summary.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import Model, { attr } from '@ember-data/model';

import { categories } from '../helpers/target-profile-categories';
export default class TargetProfileSummary extends Model {
@attr() name;
@attr() outdated;
@attr() category;
@attr() createdAt;
@attr() canDetach;

get translationKeyCategory() {
return categories[this.category];
}
}
3 changes: 3 additions & 0 deletions admin/app/routes/authenticated/target-profiles/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export default class ListRoute extends Route {
pageSize: { refreshModel: true },
id: { refreshModel: true },
name: { refreshModel: true },
categories: { refreshModel: true },
};

beforeModel() {
Expand All @@ -25,6 +26,7 @@ export default class ListRoute extends Route {
filter: {
id: params.id ? params.id.trim() : '',
name: params.name ? params.name.trim() : '',
categories: params.categories ?? [],
},
page: {
number: params.pageNumber,
Expand All @@ -46,6 +48,7 @@ export default class ListRoute extends Route {
controller.pageSize = 10;
controller.id = null;
controller.name = null;
controller.categories = [];
}
}
}
8 changes: 8 additions & 0 deletions admin/app/styles/globals/page.scss
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,12 @@
}
}
}

.page-body-template {
padding: var(--pix-spacing-8x);

&__content {
margin-bottom: var(--pix-spacing-8x);
}
}
}
3 changes: 2 additions & 1 deletion admin/app/styles/globals/table-admin.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* stylelint-disable selector-class-pattern */
.table-admin {
margin-bottom: $pix-spacing-s;
margin-bottom: var(--pix-spacing-2x);
background-color: var(--pix-neutral-0);

thead label {
margin-bottom: 0;
Expand Down
6 changes: 4 additions & 2 deletions admin/app/templates/authenticated/target-profiles/list.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
</div>
</header>

<main class="page-body">
<section class="page-section">
<main class="page-body-template">
<section>
<TargetProfiles::ListSummaryItems
@summaries={{@model}}
@id={{this.id}}
@name={{this.name}}
@categories={{this.categories}}
@triggerFiltering={{this.triggerFiltering}}
@onResetFilter={{this.onResetFilter}}
/>
</section>
</main>
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import { clickByName, visit } from '@1024pix/ember-testing-library';
import { currentURL } from '@ember/test-helpers';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { t } from 'ember-intl/test-support';
import { setupApplicationTest } from 'ember-qunit';
import { authenticateAdminMemberWithRole } from 'pix-admin/tests/helpers/test-init';
import { module, test } from 'qunit';

import setupIntl from '../../../helpers/setup-intl';

module('Acceptance | Target Profiles | List', function (hooks) {
setupApplicationTest(hooks);
setupMirage(hooks);
setupIntl(hooks);

module('When admin member is not logged in', function () {
test('it should not be accessible by an unauthenticated user', async function (assert) {
Expand Down Expand Up @@ -104,7 +108,9 @@ module('Acceptance | Target Profiles | List', function (hooks) {
const screen = await visit('/target-profiles/list?id=123');

// then
assert.dom(screen.getByRole('textbox', { name: 'Filtrer les profils cible par un id' })).hasValue('123');
assert
.dom(screen.getByRole('textbox', { name: t('pages.target-profiles.filters.search-by-id.name') }))
.hasValue('123');
});
});
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { render } from '@1024pix/ember-testing-library';
import { setupRenderingTest } from 'ember-qunit';
import ListSummaryItems from 'pix-admin/components/target-profiles/list-summary-items';
import { module, test } from 'qunit';

import setupIntlRenderingTest, { t } from '../../../../../helpers/setup-intl-rendering';

module('Integration | Component | routes/authenticated/target-profiles | list-items', function (hooks) {
setupRenderingTest(hooks);
setupIntlRenderingTest(hooks);

const triggerFiltering = function () {};
const goToTargetProfilePage = function () {};
Expand All @@ -18,9 +19,9 @@ module('Integration | Component | routes/authenticated/target-profiles | list-it
);

// then
assert.dom(screen.getByText('ID')).exists();
assert.dom(screen.getByText('Nom')).exists();
assert.dom(screen.getByText('Statut')).exists();
assert.ok(screen.getByText(t('common.fields.id')));
assert.ok(screen.getByText(t('common.fields.name')));
assert.ok(screen.getByText(t('common.fields.status')));
});

test('it should display search inputs', async function (assert) {
Expand All @@ -32,8 +33,8 @@ module('Integration | Component | routes/authenticated/target-profiles | list-it
);

// then
assert.dom(screen.getByRole('textbox', { name: 'Filtrer les profils cible par un id' })).exists();
assert.dom(screen.getByRole('textbox', { name: 'Filtrer les profils cible par un nom' })).exists();
assert.dom(screen.getByRole('textbox', { name: t('pages.target-profiles.filters.search-by-id.name') })).exists();
assert.dom(screen.getByRole('textbox', { name: t('pages.target-profiles.filters.search-by-name.name') })).exists();
});

test('it should display target profile summaries list', async function (assert) {
Expand Down
Loading
Loading