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] Ajout d'un formulaire pour la création d'une configuration de déroulé V3 (PIX-13065). #9385

Merged
Merged
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
16 changes: 16 additions & 0 deletions admin/app/adapters/flash-algorithm-configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import ApplicationAdapter from './application';

export default class FlashAlgorithmConfigurationAdapter extends ApplicationAdapter {
namespace = 'api/admin';

queryRecord() {
const url = `${this.host}/${this.namespace}/flash-assessment-configuration`;
return this.ajax(url, 'GET');
}

createRecord(flashAlgorithmConfiguration) {
const url = `${this.host}/${this.namespace}/flash-assessment-configuration`;
const payload = { data: flashAlgorithmConfiguration };
return this.ajax(url, 'POST', payload);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import PixButton from '@1024pix/pix-ui/components/pix-button';
import PixCheckbox from '@1024pix/pix-ui/components/pix-checkbox';
import PixInput from '@1024pix/pix-ui/components/pix-input';
import { on } from '@ember/modifier';
import { t } from 'ember-intl';

<template>
<form class="flash-algorithm-configuration-form">
<PixInput
{{on "input" @updateNumberValues}}
@id="maximumAssessmentLength"
@value={{@form.maximumAssessmentLength}}
type="number"
min="0"
>
<:label>{{t
"pages.administration.certification.flash-algorithm-configuration.form.maximumAssessmentLength"
}}</:label>
</PixInput>

<PixInput {{on "input" @updateNumberValues}} @id="warmUpLength" @value={{@form.warmUpLength}} type="number" min="0">
<:label>{{t "pages.administration.certification.flash-algorithm-configuration.form.warmUpLength"}}</:label>
</PixInput>

<PixInput
{{on "input" @updateNumberValues}}
@id="challengesBetweenSameCompetence"
@value={{@form.challengesBetweenSameCompetence}}
type="number"
min="0"
>
<:label>{{t
"pages.administration.certification.flash-algorithm-configuration.form.challengesBetweenSameCompetence"
}}</:label>
</PixInput>

<PixInput
{{on "input" @updateNumberValues}}
@id="variationPercent"
@value={{@form.variationPercent}}
type="number"
min="0"
>
<:label>{{t "pages.administration.certification.flash-algorithm-configuration.form.variationPercent"}}</:label>
</PixInput>

<PixInput
{{on "input" @updateNumberValues}}
@id="variationPercentUntil"
@value={{@form.variationPercentUntil}}
type="number"
min="0"
>
<:label>{{t
"pages.administration.certification.flash-algorithm-configuration.form.variationPercentUntil"
}}</:label>
</PixInput>

<PixInput
{{on "input" @updateNumberValues}}
@id="doubleMeasuresUntil"
@value={{@form.doubleMeasuresUntil}}
type="number"
min="0"
>
<:label>{{t "pages.administration.certification.flash-algorithm-configuration.form.doubleMeasuresUntil"}}</:label>
</PixInput>

<PixCheckbox
{{on "input" @updateCheckboxValues}}
@id="limitToOneQuestionPerTube"
@value={{@form.limitToOneQuestionPerTube}}
checked={{@form.limitToOneQuestionPerTube}}
>
<:label>{{t
"pages.administration.certification.flash-algorithm-configuration.form.limitToOneQuestionPerTube"
}}</:label>
</PixCheckbox>

<PixCheckbox
{{on "input" @updateCheckboxValues}}
@id="enablePassageByAllCompetences"
@value={{@form.enablePassageByAllCompetences}}
checked={{@form.enablePassageByAllCompetences}}
>
<:label>{{t
"pages.administration.certification.flash-algorithm-configuration.form.enablePassageByAllCompetences"
}}</:label>
</PixCheckbox>

<PixButton
class="scoring-simulator__form-button"
@type="submit"
@triggerAction={{@onCreateFlashAlgorithmConfiguration}}
>{{t "common.actions.save"}}</PixButton>
</form>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import PixBlock from '@1024pix/pix-ui/components/pix-block';
import { action } from '@ember/object';
import { service } from '@ember/service';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { t } from 'ember-intl';

import Form from './form';

export default class FlashAlgorithmConfiguration extends Component {
@service store;
@service notifications;
@tracked form = {
maximumAssessmentLength: this.args.model.maximumAssessmentLength,
warmUpLength: this.args.model.warmUpLength,
challengesBetweenSameCompetence: this.args.model.challengesBetweenSameCompetence,
variationPercent: this.args.model.variationPercent,
variationPercentUntil: this.args.model.variationPercentUntil,
doubleMeasuresUntil: this.args.model.doubleMeasuresUntil,
limitToOneQuestionPerTube: this.args.model.limitToOneQuestionPerTube,
enablePassageByAllCompetences: this.args.model.enablePassageByAllCompetences,
};

@action
async onCreateFlashAlgorithmConfiguration(event) {
event.preventDefault();
const adapter = this.store.adapterFor('flash-algorithm-configuration');
try {
await adapter.createRecord(this.form);
this.notifications.success('La configuration a été créée');
} catch (errorResponse) {
this.notifications.error("La configuration n'a pu être créée");
}
}

@action
updateNumberValues(event) {
this.form = { ...this.form, [event.target.id]: event.target.value };
}

@action
updateCheckboxValues(event) {
this.form = { ...this.form, [event.target.id]: event.target.checked };
}

<template>
<PixBlock class="page-section">

<h2 class="page-section__title">
{{t "pages.administration.certification.flash-algorithm-configuration.title"}}
</h2>

<Form
@form={{this.form}}
@updateNumberValues={{this.updateNumberValues}}
@updateCheckboxValues={{this.updateCheckboxValues}}
@onCreateFlashAlgorithmConfiguration={{this.onCreateFlashAlgorithmConfiguration}}
/>

</PixBlock>
</template>
}
11 changes: 11 additions & 0 deletions admin/app/components/administration/certification/index.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import CertificationScoringConfiguration from './certification-scoring-configuration';
import CompetenceScoringConfiguration from './competence-scoring-configuration';
import FlashAlgorithmConfiguration from './flash-algorithm-configuration';
import ScoringSimulator from './scoring-simulator';

<template>
<CertificationScoringConfiguration />
<CompetenceScoringConfiguration />
<FlashAlgorithmConfiguration @model={{@model}} />
<ScoringSimulator />
</template>
14 changes: 14 additions & 0 deletions admin/app/models/flash-algorithm-configuration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Model, { attr } from '@ember-data/model';

export default class FlashAlgorithmConfiguration extends Model {
@attr('number') warmUpLength;
@attr('number') maximumAssessmentLength;
@attr('number') challengesBetweenSameCompetence;
@attr('number') variationPercent;
@attr('number') variationPercentUntil;
@attr('number') doubleMeasuresUntil;
@attr('boolean') limitToOneQuestionPerTube;
@attr('boolean') enablePassageByAllCompetences;
@attr('array') forcedCompetences;
@attr('array') minimumEstimatedSuccessRateRanges;
}
12 changes: 12 additions & 0 deletions admin/app/routes/authenticated/administration/certification.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Route from '@ember/routing/route';
import { service } from '@ember/service';

export default class CertificationRoute extends Route {
@service store;

async model() {
return this.store.queryRecord('flash-algorithm-configuration', {
id: 0,
alexandrecoin marked this conversation as resolved.
Show resolved Hide resolved
});
}
}
1 change: 1 addition & 0 deletions admin/app/styles/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
@import 'components/administration';
@import 'components/administration/certification/certification-scoring-configuration';
@import 'components/administration/certification/competence-scoring-configuration';
@import 'components/administration/certification/flash-algorithm-configuration-form';
@import 'components/administration/certification/scoring-simulator';
@import 'components/autonomous-courses/details';
@import 'components/autonomous-courses/form';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.flash-algorithm-configuration-form {
display: flex;
flex-direction: column;
gap: var(--pix-spacing-4x);
align-items: flex-start;
margin-top: var(--pix-spacing-6x);

.pix-input__input {
width: auto;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
<Administration::Certification::CertificationScoringConfiguration />

<Administration::Certification::CompetenceScoringConfiguration />

<Administration::Certification::ScoringSimulator />
<Administration::Certification @model={{@model}} />
4 changes: 4 additions & 0 deletions admin/mirage/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ function routes() {
});
this.put('/admin/admin-members/:id/deactivate', () => {});

this.get('/admin/flash-assessment-configuration', (schema, _) => {
return schema.create('flash-algorithm-configuration');
});

this.get('/admin/sessions', findPaginatedAndFilteredSessions);
this.get('/admin/sessions/to-publish', getToBePublishedSessions);
this.get('/admin/sessions/with-required-action', getWithRequiredActionSessions);
Expand Down
4 changes: 3 additions & 1 deletion admin/tests/helpers/setup-intl-rendering.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { setupRenderingTest } from 'ember-qunit';

import setupIntl from './setup-intl';
import setupIntl, { t } from './setup-intl';

export default function setupIntlRenderingTest(hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
}

export { t };
alexandrecoin marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 3 additions & 1 deletion admin/tests/helpers/setup-intl.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { setupIntl as setupIntlFromEmberIntl } from 'ember-intl/test-support';
import { setupIntl as setupIntlFromEmberIntl, t } from 'ember-intl/test-support';

export default function setupIntl(hooks, locale = ['fr']) {
setupIntlFromEmberIntl(hooks, locale[0]);
Expand All @@ -8,3 +8,5 @@ export default function setupIntl(hooks, locale = ['fr']) {
this.dayjs.setLocale(locale[0]);
});
}

export { t };
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { render } from '@1024pix/ember-testing-library';
import FlashAlgorithmConfiguration from 'pix-admin/components/administration/certification/flash-algorithm-configuration';
import { module, test } from 'qunit';

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

module('Integration | Component | administration/certification/flash-algorithm-configuration', function (hooks) {
setupIntlRenderingTest(hooks);

test('should display all details', async function (assert) {
// given
const flashAlgorithmConfiguration = {
maximumAssessmentLength: 1,
warmUpLength: 2,
challengesBetweenSameCompetence: 3,
variationPercent: 4,
variationPercentUntil: 5,
doubleMeasuresUntil: 6,
limitToOneQuestionPerTube: true,
enablePassageByAllCompetences: false,
};

// when
const screen = await render(
<template><FlashAlgorithmConfiguration @model={{flashAlgorithmConfiguration}} /></template>,
);

// then
const maximumAssessmentLength = await screen.getByRole('spinbutton', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.maximumAssessmentLength'),
}).value;
const warmUpLength = await screen.getByRole('spinbutton', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.warmUpLength'),
}).value;
const challengesBetweenSameCompetence = await screen.getByRole('spinbutton', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.challengesBetweenSameCompetence'),
}).value;
const variationPercent = await screen.getByRole('spinbutton', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.variationPercent'),
}).value;
const variationPercentUntil = await screen.getByRole('spinbutton', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.variationPercentUntil'),
}).value;
const doubleMeasuresUntil = await screen.getByRole('spinbutton', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.doubleMeasuresUntil'),
}).value;
const limitToOneQuestionPerTube = await screen.getByRole('checkbox', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.limitToOneQuestionPerTube'),
}).checked;
const enablePassageByAllCompetences = await screen.getByRole('checkbox', {
name: t('pages.administration.certification.flash-algorithm-configuration.form.enablePassageByAllCompetences'),
}).checked;

assert.strictEqual(maximumAssessmentLength, '1');
assert.strictEqual(warmUpLength, '2');
assert.strictEqual(challengesBetweenSameCompetence, '3');
assert.strictEqual(variationPercent, '4');
assert.strictEqual(variationPercentUntil, '5');
assert.strictEqual(doubleMeasuresUntil, '6');
assert.true(limitToOneQuestionPerTube);
assert.false(enablePassageByAllCompetences);
});
});
42 changes: 42 additions & 0 deletions admin/tests/unit/adapters/flash-algorithm-configuration_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { setupTest } from 'ember-qunit';
import ENV from 'pix-admin/config/environment';
import { module, test } from 'qunit';
import sinon from 'sinon';

module('Unit | Adapters | flash-algorithm-configuration', function (hooks) {
setupTest(hooks);

module('#queryRecord', () => {
test('should build query url', async function (assert) {
// given
const adapter = this.owner.lookup('adapter:flash-algorithm-configuration');
sinon.stub(adapter, 'ajax');

// when
adapter.queryRecord();

// then
const expectedUrl = `${ENV.APP.API_HOST}/api/admin/flash-assessment-configuration`;
sinon.assert.calledWith(adapter.ajax, expectedUrl, 'GET');
assert.ok(adapter);
});
});

module('#createRecord', () => {
test('should call the post url with the correct payload', async function (assert) {
// given
const flashAlgorithmConfiguration = { warmUpLength: 2 };
const payload = { data: flashAlgorithmConfiguration };
const adapter = this.owner.lookup('adapter:flash-algorithm-configuration');
sinon.stub(adapter, 'ajax');

// when
adapter.createRecord(flashAlgorithmConfiguration);

// then
const expectedUrl = `${ENV.APP.API_HOST}/api/admin/flash-assessment-configuration`;
sinon.assert.calledWith(adapter.ajax, expectedUrl, 'POST', payload);
assert.ok(adapter);
});
});
});
Loading