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

SCENARIO: select items from a acorpus (#155) #577

Open
wants to merge 3 commits into
base: v7
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
23 changes: 23 additions & 0 deletions features/item_select_from_given_corpus.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#language: fr

Fonctionnalité: (Dé)sélectionner les items d'un ou de plusieurs corpus


Scénario: L'utilisateur désélectionne un corpus parmi plusieurs

Soit un portfolio ouvert
Et tous les corpus sont sélectionnés
Et "SJ 020" un des items affichés
Et "AXN 009" un des items affichés
Quand l'utilisateur désélectionne le corpus "corpus : Vitraux - Bénel"
Alors l'item "AXN 009" est affiché
Mais l'item "SJ 020" est caché

Scénario: L'utilisateur sélectionne plusieurs corpus

Soit un portfolio ouvert
Et aucun des corpus n'est sélectionné
Et aucun item n'est affiché
Quand l'utilisateur sélectionne les corpus "corpus : Vitraux - Bénel" et "corpus : Vitraux - Dr. Krieger"
Alors l'item "SJ 020" est affiché
Et l'item "PSM 002" est affiché
15 changes: 15 additions & 0 deletions features/step_definitions/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,18 @@
page.current_window.resize_to(320, 480)
end

Soit("tous les corpus sont sélectionnés") do
find(:css, ".corpus_checkbox[value='corpus : Vitraux - Bénel']").set(true)
find(:css, ".corpus_checkbox[value='corpus : Vitraux - Dr. Krieger']").set(true)
find(:css, ".corpus_checkbox[value='corpus : Vitraux - Recensement']").set(true)
end

Soit("aucun des corpus n'est sélectionné") do
find(".corpus_checkbox[value='corpus : Vitraux - Bénel']").set(false)
find(".corpus_checkbox[value='corpus : Vitraux - Dr. Krieger']").set(false)
find(".corpus_checkbox[value='corpus : Vitraux - Recensement']").set(false)
end

Soit("aucun item n'est affiché") do
expect(page).not_to have_selector ".Item"
end
10 changes: 9 additions & 1 deletion features/step_definitions/event.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
Quand("l'utilisateur indique {string} comme valeur de l'attribut {string}") do |value, attribute|
within '.Attributes' do
fill_in placeholder: 'Ajouter un attribut et une valeur...', with: "#{attribute}:#{value}"
click_on class: 'ValidateButton'
click_on class: 'ValidateButton'
end
end

Expand Down Expand Up @@ -96,3 +96,11 @@
end
end

Quand("l'utilisateur désélectionne le corpus {string}") do |corpus|
find(".corpus_checkbox[value='#{corpus}']").set(false)
end

Quand("l'utilisateur sélectionne les corpus {string} et {string}") do |corpus1, corpus2|
find(".corpus_checkbox[value='#{corpus1}']").set(true)
find(".corpus_checkbox[value='#{corpus2}']").set(true)
end
43 changes: 43 additions & 0 deletions src/Selection.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,49 @@ export default class Selection {
clause.type = (clause.type === 'intersection') ? 'union' : 'intersection';
}

addCorpus = (corpusId) => {
const existing = this.selectionJSON.data.some(e =>
e.selection.find(corpus => corpus === corpusId)
|| e.exclusion.find(corpus => corpus === corpusId)
);
if (!existing) {
this.selectionJSON.data = [];
this.selectionJSON.data.push({type: 'intersection', selection: [], exclusion: [corpusId]});
}
}

toggleCorpus = (corpusId) => {
const existingClause = this.selectionJSON.data.find(s => {
const allTopics = [...s.selection, ...s.exclusion];
if (allTopics.length === 0) {
return false;
}
return true;
});
if (existingClause) {
this.testSwitchPlace(existingClause, corpusId, false, true);
if ([...existingClause.selection, ...existingClause.exclusion].length === 0)
this.selectionJSON.data.splice(this.selectionJSON.data.indexOf(existingClause), 1);
} else {
this.addCorpus(corpusId);
}
}

testSwitchPlace = (clause, criterion, toDelete, threeState) => {
let index;
if ((index = clause.selection.indexOf(criterion)) > -1) {
clause.selection.splice(index, 1);
if (!toDelete)
clause.exclusion.push(criterion);
} else if ((index = clause.exclusion.indexOf(criterion)) > -1) {
clause.exclusion.splice(index, 1);
if (!toDelete && !threeState)
clause.selection.push(criterion);
} else {
clause.exclusion.push(criterion);
}
};

getClauses = () => this.selectionJSON.data;

getMainClause = () => this.selectionJSON;
Expand Down
2 changes: 1 addition & 1 deletion src/components/portfolioPage/Badge.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Badge extends Component {
{this.props.name}
<button className={'badge badge-pill badge-dark oi ml-1 border-0 ' + (this.props.exclusion ? 'oi-plus' : 'oi-minus')}
title={this.props.exclusion ? t`Inclure` : t`Exclure`}
onClick={this.handleChangeState}
onClick={!this.props.id.includes('corpus') ? this.handleChangeState : this.handleDeletion}
> </button>
<button className="badge badge-pill badge-dark oi oi-x border-0"
title={t`Déselectionner`}
Expand Down
52 changes: 48 additions & 4 deletions src/components/portfolioPage/Corpora.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,32 @@ import memoize from 'memoize-one';
import ItemCreator from './ItemCreator.jsx';
import GeographicMap from './GeographicMap.jsx';
import { Items } from '../../model.js';
import Selection from '../../Selection.js';

class Corpora extends Component {

state = {
criteria: 'name'
criteria: 'name',
listCorpus: [],
firstReceive: false,
};

sort = memoize((items, criteria) => items.sort(by(`${criteria}.0`)));

componentDidUpdate(prevProps) {
if (this.props.ids.length !== prevProps.ids.length) {
let listFormated = [...this.props.ids];
listFormated = listFormated.map(corpus => {
corpus = 'corpus : '.concat(corpus);
return corpus;
});
this.setState({
listCorpus: listFormated,
firstReceive: true,
});
}
}

render() {
let itemsData = this.sort(this.props.items, this.state.criteria);
let items = itemsData.map(x =>
Expand All @@ -23,8 +40,10 @@ class Corpora extends Component {
let options = this._getOptions(attributes);
let count = this.props.items.length;
let total = this.props.from;
let listIds = this.props.ids.map((corpus) =>
<div key={corpus}>{corpus} <ItemCreator corpus={corpus} conf={this.props.conf} /></div>
let listIds = this.props.ids.map((corpus) =>{
let corpusFormated = 'corpus : '.concat(corpus);
return <div key={corpusFormated}> <input className="corpus_checkbox" type="checkbox" value={corpusFormated} onChange={this.handleChange} checked={this.isChecked(corpusFormated)}/> {corpus} <ItemCreator corpus={corpus} conf={this.props.conf} /></div>;
}
);
return (
<div className="col-md-8 p-4">
Expand Down Expand Up @@ -63,12 +82,37 @@ class Corpora extends Component {
<option key={attribute} value={attribute}> {attribute} </option>
));
}

handleChange = (e) => {
let list = this.state.listCorpus;
let index = list.indexOf(e.target.value);
if (index !== -1) {
list.splice(index, 1);
} else {
list.push(e.target.value);
}
this.setState({
listCorpus: list
});
this.handleCorpusSelected(e.target.value);
}

isChecked(corpus) {
const selection = Selection.fromURI();
return selection.isSelectedOrExcluded(corpus) !== 'Excluded';
}

handleCorpusSelected(corpusId) {
const selection = Selection.fromURI();
selection.toggleCorpus(corpusId);
this.props.history.push(selection.toURI());
}
}

function Item(props) {
let uri = `/item/${props.item.corpus}/${props.item.id}`;
let name = [props.item.name].join(', '); //Name can be an array
let thumbnail = props.item.thumbnail && <img src={props.item.thumbnail} alt={name}/>;
let thumbnail = props.item.thumbnail && <img src={props.item.thumbnail} alt={name} />;
let criteria = (props.criteria !== 'name')
&& <div className="About"> {props.item[props.criteria]} </div>;
return (
Expand Down
4 changes: 3 additions & 1 deletion src/components/portfolioPage/Portfolio.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,11 @@ class Portfolio extends Component {
}

_getItemAttributes(item) {
return new Items(
let result = new Items(
[item]
).getAttributes()
.map(([key, value]) => key.concat(' : ', value.replace('\'', '’')));
return result;
}

_isSelected(item) {
Expand Down Expand Up @@ -260,6 +261,7 @@ class Portfolio extends Component {
from={this.state.items.length}
items={this.state.selectedItems}
conf={conf}
history={this.props.history}
/>
);
}
Expand Down
6 changes: 5 additions & 1 deletion src/components/portfolioPage/SearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ class SearchBar extends React.Component {
handleSuggestionSelected = (_, { suggestion }) => {
this.setState({pattern: ''});
const selection = Selection.fromURI();
selection.addTopic(suggestion.id);
if (suggestion.id.includes('corpus')) {
selection.addCorpus(suggestion.id);
} else {
selection.addTopic(suggestion.id);
}
this.props.history.push(selection.toURI());
};

Expand Down
12 changes: 7 additions & 5 deletions src/components/portfolioPage/Status.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ class Status extends Component {
...clause.exclusion.map(id => ({excluded: true, id, topic: this._getCandidate(id)}))]
.sort(filter)
.map(
t =>
(t.topic === null)
? <Trans>Rubrique inconnue</Trans>
: <Badge exclusion={t.excluded} id={t.id} name={t.topic.name} _changeItemState={this._changeItemState}/>
t => {
let res = (t.topic === null) ? <Trans>Rubrique inconnue</Trans> : <Badge exclusion={t.excluded} id={t.id} name={t.topic.name} _changeItemState={this._changeItemState}/>;
return res;
}
);
status.push(topicsHTML.map((e, i) => i < topicsHTML.length - 1 ? [e, <Button clause={clause} _changeUnionState={this._changeUnionState}/>] : [e]).reduce((a, b) => a.concat(b))
);
Expand All @@ -38,7 +38,9 @@ class Status extends Component {

_getCandidate(id) {
for (let v of this.props.candidates) {
if (v[id]) return v[id];
if (v[id]) {
return v[id];
}
}
return null;
}
Expand Down
5 changes: 3 additions & 2 deletions src/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ class Items {
this.items
.map(
x => Object.entries(x).filter(
y => !['topic', 'resource', 'thumbnail', 'id', 'item', 'corpus', 'record', 'original', '_attachments'].includes(y[0])
y => !['topic', 'resource', 'thumbnail', 'id', 'item', 'record', 'original', '_attachments'].includes(y[0])
)
)
.reduce((x, y) => x.concat(y), [])
.map(([x, y]) => JSON.stringify([x, y[0]]))
.map(([x, y]) => Array.isArray(y) ? [x, y[0]] : [x, y])
.map(JSON.stringify)
)].map(JSON.parse);

getAttributeKeys = () => [...new Set(this.getAttributes().map(x => x[0]))];
Expand Down