Skip to content
Draft
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
7 changes: 7 additions & 0 deletions frontend/scenarios/create_document.feature
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,10 @@ Scénario: en gardant certaines des métadonnées du document source
"""
dc_isPartOf: Archéologie préventive (IF14)
"""
Scénario: En tant qu'hexaple par sélection de plusieurs documents
Soit la liste des documents affichée
Et une session active avec mon compte
Et ayant sélectionné les documents "Traduction A" et "Traduction B"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When you mention data, they must really exist in the sample data.

Quand j'essaie de créer une glose de type "Quotation"
Alors la glose ouverte contient les références à "Traduction A"
Copy link
Copy Markdown
Member

@benel benel Jun 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should mention real content related to your included document.

Et la glose ouverte contient les références à "Traduction B"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should mention real content related to your included document.

42 changes: 36 additions & 6 deletions frontend/src/components/DocumentsCards.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import Card from 'react-bootstrap/Card';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
import Form from 'react-bootstrap/Form';
import Metadata from './Metadata';
import BrowseTools from './BrowseTools';
import FutureDocument from './FutureDocument';
import { TypeBadge } from './Type';

function DocumentsCards({docs, expandable, byRow, createOn, setLastUpdate, backend, user}) {
function DocumentsCards({docs, expandable, byRow, createOn, setLastUpdate, backend, user, selectedDocs, setSelectedDocs, showCheckboxes}) {
return (
<Row className="gy-4">
{docs.map(x => x?._id && x?.dc_title &&
<Col key={x._id} md={ byRow && (12 / byRow) }>
<DocumentCard doc={x} expandable={expandable} />
<DocumentCard
doc={x}
expandable={expandable}
selectedDocs={selectedDocs}
setSelectedDocs={setSelectedDocs}
showCheckboxes={showCheckboxes}
/>
</Col>
)}
{createOn &&
Expand All @@ -27,16 +34,39 @@ function DocumentsCards({docs, expandable, byRow, createOn, setLastUpdate, backe
);
}

function DocumentCard({doc, expandable}) {
function DocumentCard({doc, expandable, selectedDocs, setSelectedDocs, showCheckboxes}) {
const handleCheck = (e) => {
if (e.target.checked) {
setSelectedDocs(prev => [...prev, doc._id]);
} else {
setSelectedDocs(prev => prev.filter(id => id !== doc._id));
}
};

return (
<Card className="h-100">
<Card className="h-100 position-relative">
<Card.Body>
<BrowseTools id={doc._id} openable={expandable} />
<div className="d-flex align-items-start gap-2 mb-2">
{/* La checkbox s'affiche uniquement si showCheckboxes est vrai */}
{showCheckboxes && (
<Form.Check
type="checkbox"
id={`check-${doc._id}`}
className="me-1"
style={{ cursor: 'pointer' }}
checked={selectedDocs?.includes(doc._id) || false}
onChange={handleCheck}
/>
)}
<div className="flex-grow-1">
<BrowseTools id={doc._id} openable={expandable} />
</div>
</div>
<Metadata metadata={doc} />
<TypeBadge type={doc?.type}/>
</Card.Body>
</Card>
);
}

export default DocumentsCards;
export default DocumentsCards;
63 changes: 58 additions & 5 deletions frontend/src/routes/Bookshelf.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,31 @@
import '../styles/Bookshelf.css';
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router';
import Container from 'react-bootstrap/Container';
import ButtonGroup from 'react-bootstrap/ButtonGroup';
import ToggleButton from 'react-bootstrap/ToggleButton';
import Button from 'react-bootstrap/Button';
import FutureDocument from '../components/FutureDocument.jsx';
import DocumentsCards from '../components/DocumentsCards.jsx';
import Graph from '../components/Graph.jsx';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
import { v4 as uuid } from 'uuid';

function Bookshelf({ backend, user }) {
const [documents, setDocuments] = useState([]);
const [lastUpdate, setLastUpdate] = useState();
const [displayMode, setDisplayMode] = useState(localStorage.getItem('displayMode') || 'graph');
const [selectedDocs, setSelectedDocs] = useState([]);

const navigate = useNavigate();
const displayModesList = ['graph', 'list'];

useEffect(() => {
backend.getAllDocuments(user)
.then(setDocuments);
}, [lastUpdate, user, backend]);

const docs = [
...new Map(
documents?.filter(x => !!x)
Expand All @@ -28,6 +34,34 @@ function Bookshelf({ backend, user }) {
];
const displayedDocs = docs?.flatMap(d => d[0]);

const handleCreateQuotation = async () => {
const _id = uuid().replace(/-/g, '');
const doc = {
_id,
editors: [user],
dc_creator: '…',
dc_title: '…',
dc_issued: new Date(),
dc_isPartOf: null,
dc_license: null,
dc_translator: null,
dc_language: null,
dc_publisher: null,
dc_spatial: null,
text: '…',
links: selectedDocs.map((object) => ({ verb: 'includes', object }))
};

try {
await backend.putDocument(doc);
setLastUpdate(_id);
setSelectedDocs([]);
navigate(`/${_id}#${_id}`);
} catch (error) {
console.error(error);
}
};

function DisplayDocuments() {
switch (displayMode) {
case 'graph':
Expand All @@ -42,9 +76,29 @@ function Bookshelf({ backend, user }) {
</Row>
);
case 'list':
return <DocumentsCards docs={documents} byRow={4} createOn={[]}
{...{setLastUpdate, backend, user}}
/>;
return (
<>
{selectedDocs.length > 0 && (
<div className="card p-3 mb-4 justify-content-between align-items-center flex-direction-row">
<div>Create a new quotation with the <strong>{selectedDocs.length}</strong> selected document(s)</div>
<Button variant="outline-danger" onClick={handleCreateQuotation}>
Create Quotation
</Button>
</div>
)}
<DocumentsCards
docs={documents}
byRow={4}
createOn={[]}
selectedDocs={selectedDocs}
setSelectedDocs={setSelectedDocs}
showCheckboxes={true}
{...{setLastUpdate, backend, user}}
/>
</>
);
default:
return null;
}
}

Expand Down Expand Up @@ -75,5 +129,4 @@ function Bookshelf({ backend, user }) {
);
}

export default Bookshelf;

export default Bookshelf;
4 changes: 4 additions & 0 deletions frontend/tests/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,7 @@ Soit("{string} le nom de la licence du document principal", (license) => {
cy.get('.license').eq(0).should('contain', license);
});

Soit("ayant sélectionné les documents {string} et {string}", (doc1, doc2) => {
cy.contains('.list-group-item', doc1).find('input[type="checkbox"]').check();
cy.contains('.list-group-item', doc2).find('input[type="checkbox"]').check();
});
5 changes: 5 additions & 0 deletions frontend/tests/outcome.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,8 @@ Alors("{string} est à la ligne {int} du passage", (text, line) => {
});
});

Alors("la glose ouverte contient les références à {string}", (title) => {
cy.get('.scholium .sources')
.should('be.visible')
.and('contain', title);
});
Loading