Skip to content

Commit

Permalink
Merge pull request #589 from kbss-cvut/development
Browse files Browse the repository at this point in the history
[3.4.0] Release
  • Loading branch information
ledsoft authored Dec 3, 2024
2 parents 0f3985f + 0b0f407 commit 027b5cc
Show file tree
Hide file tree
Showing 58 changed files with 1,044 additions and 409 deletions.
7 changes: 7 additions & 0 deletions NEWS.cs.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#### Verze 3.4.0

- Přidána podpora pro záznamy o smazání pojmů. Ty jsou zobrazovány i v grafu aktivity slovníku.
- Přidána možnost filtrovat v historii změn.
- Přidána podpora pro ukládání a anotaci souborů v různých jazycích v rámci jednoho slovníku.
- Přidána podpora pro import překladů pojmů ze souboru MS Excel.

#### Verze 3.3.0

- Přidána možnost stáhnout anotovaný soubor bez nepotvrzených výskytů.
Expand Down
7 changes: 7 additions & 0 deletions NEWS.en.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
#### Version 3.4.0

- Added support for term deletion records. Term deletion events are also displayed in the vocabulary activity diagram.
- Added support for filtering in change history.
- Added support for saving and annotating files in multiple languages.
- Added support for importing term translations from an MS Excel file.

#### Version 3.3.0

- Added the possibility to download annotated file without unconfirmed occurrences.
Expand Down
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "termit-ui",
"version": "3.3.1",
"version": "3.4.0",
"private": true,
"homepage": ".",
"license": "GPL-3.0-only",
Expand Down Expand Up @@ -83,7 +83,7 @@
"@redux-devtools/extension": "^3.2.5",
"@types/enzyme": "^3.10.13",
"@types/jest": "^27.4.1",
"@types/js-cookie": "^3.0.3",
"@types/js-cookie": "^3.0.6",
"@types/lodash": "^4.17.10",
"@types/luxon": "^3.4.2",
"@types/node": "^18.11.17",
Expand Down
21 changes: 18 additions & 3 deletions src/action/AsyncActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import * as jsonld from "jsonld";
import Message from "../model/Message";
import MessageType from "../model/MessageType";
import Term, { CONTEXT as TERM_CONTEXT, TermData } from "../model/Term";
import VocabularyUtils, { IRI } from "../util/VocabularyUtils";
import VocabularyUtils, { IRI, IRIImpl } from "../util/VocabularyUtils";
import ActionType, { PendingAsyncAction } from "./ActionType";
import Resource, { ResourceData } from "../model/Resource";
import RdfsResource, {
Expand Down Expand Up @@ -61,6 +61,10 @@ import UserRole, { UserRoleData } from "../model/UserRole";
import { loadTermCount } from "./AsyncVocabularyActions";
import { getApiPrefix } from "./ActionUtils";
import { getShortLocale } from "../util/IntlUtil";
import {
getChangeTypeUri,
VocabularyContentChangeFilterData,
} from "../model/filter/VocabularyContentChangeFilterData";

/*
* Asynchronous actions involve requests to the backend server REST API. As per recommendations in the Redux docs, this consists
Expand Down Expand Up @@ -146,6 +150,7 @@ export function createVocabulary(vocabulary: Vocabulary) {
export function loadVocabulary(iri: IRI, timestamp?: string) {
const action = {
type: ActionType.LOAD_VOCABULARY,
iri: IRIImpl.toString(iri),
};
return (dispatch: ThunkDispatch, getState: () => TermItState) => {
if (isActionRequestPending(getState(), action)) {
Expand Down Expand Up @@ -1130,13 +1135,23 @@ export function loadLatestTextAnalysisRecord(resourceIri: IRI) {
};
}

export function loadHistory(asset: Asset) {
export function loadHistory(
asset: Asset,
filterData?: VocabularyContentChangeFilterData
) {
const assetIri = VocabularyUtils.create(asset.iri);
const historyConf = resolveHistoryLoadingParams(asset, assetIri);
const action = { type: historyConf.actionType };
return (dispatch: ThunkDispatch) => {
dispatch(asyncActionRequest(action, true));
return Ajax.get(historyConf.url, param("namespace", assetIri.namespace))
let params = param("namespace", assetIri.namespace);
if (filterData) {
for (const [key, value] of Object.entries(filterData)) {
params = params.param(key, value);
}
params = params.param("type", getChangeTypeUri(filterData));
}
return Ajax.get(historyConf.url, params)
.then((data) =>
JsonLdUtils.compactAndResolveReferencesAsArray<ChangeRecordData>(
data,
Expand Down
16 changes: 13 additions & 3 deletions src/action/AsyncImportActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@ import { Action } from "redux";
import { loadVocabulary } from "./AsyncActions";
import Utils from "../util/Utils";

export function importIntoExistingVocabulary(vocabularyIri: IRI, data: File) {
export function importIntoExistingVocabulary(
vocabularyIri: IRI,
data: File,
translationsOnly: boolean = false
) {
const action = { type: ActionType.IMPORT_VOCABULARY };
const formData = new FormData();
formData.append("file", data, "thesaurus");
formData.append("namespace", vocabularyIri.namespace!);
if (translationsOnly) {
formData.append("translationsOnly", true.toString());
}
return (dispatch: ThunkDispatch) => {
dispatch(asyncActionRequest(action, true));
return Ajax.post(
Expand Down Expand Up @@ -82,13 +89,16 @@ const processError =
);
};

export function downloadExcelTemplate() {
export function downloadExcelTemplate(translationsOnly: boolean = false) {
return (dispatch: ThunkDispatch) => {
const action = { type: ActionType.LOAD_EXCEL_TEMPLATE };
dispatch(asyncActionRequest(action, true));
return Ajax.getRaw(
`${Constants.API_PREFIX}/vocabularies/import/template`,
responseType("arraybuffer")
responseType("arraybuffer").param(
"translationsOnly",
translationsOnly.toString()
)
)
.then((response) => {
Utils.fileDownload(
Expand Down
30 changes: 27 additions & 3 deletions src/action/AsyncVocabularyActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ import ChangeRecord, {
CONTEXT as CHANGE_RECORD_CONTEXT,
} from "../model/changetracking/ChangeRecord";
import AssetFactory from "../util/AssetFactory";
import {
getChangeTypeUri,
VocabularyContentChangeFilterData,
} from "../model/filter/VocabularyContentChangeFilterData";
import { getLocalized } from "../model/MultilingualString";

export function loadTermCount(vocabularyIri: IRI) {
const action = { type: ActionType.LOAD_TERM_COUNT, vocabularyIri };
Expand Down Expand Up @@ -137,6 +142,7 @@ export function loadVocabularyContentChanges(vocabularyIri: IRI) {

export function loadVocabularyContentDetailedChanges(
vocabularyIri: IRI,
filterData: VocabularyContentChangeFilterData,
pageReq: PageRequest
) {
const action = {
Expand All @@ -145,18 +151,36 @@ export function loadVocabularyContentDetailedChanges(

return (dispatch: ThunkDispatch) => {
dispatch(asyncActionRequest(action, true));
let params = param("namespace", vocabularyIri.namespace)
.param("page", pageReq.page?.toString())
.param("size", pageReq.size?.toString());
for (const [key, value] of Object.entries(filterData)) {
params = params.param(key, value);
}
params = params.param("type", getChangeTypeUri(filterData));
return Ajax.get(
`${Constants.API_PREFIX}/vocabularies/${vocabularyIri.fragment}/history-of-content/detail`,
param("namespace", vocabularyIri.namespace)
.param("page", pageReq.page?.toString())
.param("size", pageReq.size?.toString())
params
)
.then((data) =>
JsonLdUtils.compactAndResolveReferencesAsArray<ChangeRecord>(
data,
CHANGE_RECORD_CONTEXT
)
)
.then((data: ChangeRecord[]) => {
// adding labels to the label cache as they cannot be fetched from server
const labels: { [key: string]: string } = {};
data.forEach((r) => {
if (r["label"]) {
labels[r.changedEntity.iri] = getLocalized(r["label"]);
}
});
dispatch(
asyncActionSuccessWithPayload({ type: ActionType.GET_LABEL }, labels)
);
return data;
})
.then((data: ChangeRecord[]) => {
dispatch(asyncActionSuccess(action));
return data.map((r) => AssetFactory.createChangeRecord(r));
Expand Down
2 changes: 2 additions & 0 deletions src/component/annotator/Annotation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface AnnotationProps extends AnnotationSpanProps {
accessLevel: AccessLevel;
highlight?: boolean;
filter: AnnotatorLegendFilter;
language?: string;
}

interface AnnotationState {
Expand Down Expand Up @@ -316,6 +317,7 @@ export class Annotation extends React.Component<
onToggleDetailOpen={this.toggleOpenDetail}
onClose={this.onCloseDetail}
accessLevel={this.props.accessLevel}
language={this.props.language}
/>
);
}
Expand Down
6 changes: 5 additions & 1 deletion src/component/annotator/Annotator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ interface AnnotatorProps extends HasI18n {
user: User;
file: File;
vocabulary: Vocabulary;
annotationLanguage?: string;

onUpdate: (newHtml: string) => void;
setAnnotatorLegendFilter: (
Expand Down Expand Up @@ -625,7 +626,7 @@ export class Annotator extends React.Component<AnnotatorProps, AnnotatorState> {
<HeaderWithActions
title={this.renderTitle()}
className={classNames("annotator-header", {
"annotator-header-scrolled": window.pageYOffset > 0,
"annotator-header-scrolled": window.scrollY > 0,
})}
actions={[
<HighlightTermOccurrencesButton
Expand Down Expand Up @@ -708,6 +709,9 @@ export class Annotator extends React.Component<AnnotatorProps, AnnotatorState> {
onRemove={this.onRemove}
onResetSticky={this.resetStickyAnnotationId}
highlightedTerm={this.state.highlightedTerm}
annotationLanguage={
this.props.annotationLanguage || this.props.file.language
}
/>
</div>
</CardBody>
Expand Down
4 changes: 4 additions & 0 deletions src/component/annotator/AnnotatorContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface AnnotatorContentProps {
content: DomHandlerNode[];
accessLevel: AccessLevel; // The level of access rights the current user has
highlightedTerm: TermData | null;
annotationLanguage?: string;

onRemove: (annotationId: string | string[]) => void;
onUpdate: (annotationSpan: AnnotationSpanProps, term: Term | null) => void;
Expand Down Expand Up @@ -64,6 +65,7 @@ const AnnotatorContent: React.FC<AnnotatorContentProps> = (props) => {
onCreateTerm,
accessLevel,
highlightedTerm,
annotationLanguage,
} = props;

// Using memoization to skip processing and re-rendering of the content DOM in case it hasn't changed
Expand Down Expand Up @@ -112,6 +114,7 @@ const AnnotatorContent: React.FC<AnnotatorContentProps> = (props) => {
highlightedTerm !== null &&
elem.attribs.resource === highlightedTerm.iri
}
language={annotationLanguage}
{...attribs}
>
{children}
Expand Down Expand Up @@ -142,6 +145,7 @@ const AnnotatorContent: React.FC<AnnotatorContentProps> = (props) => {
onCreateTerm,
accessLevel,
highlightedTerm,
annotationLanguage,
]);

return (
Expand Down
2 changes: 2 additions & 0 deletions src/component/annotator/TermDefinitionAnnotation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ interface TermDefinitionAnnotationProps {
text: string;
isOpen: boolean;
accessLevel: AccessLevel;
language?: string;

onRemove: () => void;
onSelectTerm: (term: Term | null) => void;
Expand Down Expand Up @@ -118,6 +119,7 @@ export const TermDefinitionAnnotation: React.FC<
term={term}
resource={props.resource}
textContent={props.text}
language={props.language}
/>
);

Expand Down
3 changes: 2 additions & 1 deletion src/component/annotator/TermDefinitionAnnotationView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ interface TermDefinitionAnnotationViewProps {
term?: Term | null;
resource?: string;
textContent: string;
language?: string;
}

const TermDefinitionAnnotationView: React.FC<
Expand All @@ -20,7 +21,7 @@ const TermDefinitionAnnotationView: React.FC<
<tr>
<td className="label">{i18n("annotation.definition.term")}</td>
<td>
<TermLink term={props.term} />
<TermLink term={props.term} language={props.language} />
</td>
</tr>
</tbody>
Expand Down
2 changes: 2 additions & 0 deletions src/component/annotator/TermOccurrenceAnnotation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface TermOccurrenceAnnotationProps {
annotationOrigin: string;
isOpen: boolean;
accessLevel: AccessLevel;
language?: string;

onRemove: () => void;
onSelectTerm: (term: Term | null) => void;
Expand Down Expand Up @@ -129,6 +130,7 @@ export const TermOccurrenceAnnotation: React.FC<
score={props.score}
resource={props.resource}
annotationClass={props.annotationClass}
language={props.language}
/>
);

Expand Down
3 changes: 2 additions & 1 deletion src/component/annotator/TermOccurrenceAnnotationView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ interface TermOccurrenceAnnotationViewProps {
score?: string;
resource?: string;
annotationClass: string;
language?: string;
}

const TermOccurrenceAnnotationView: React.FC<
Expand All @@ -25,7 +26,7 @@ const TermOccurrenceAnnotationView: React.FC<
{i18n("annotation.term.assigned-occurrence.termLabel")}
</td>
<td>
<TermLink term={props.term!} />
<TermLink term={props.term!} language={props.language} />
</td>
</tr>
</tbody>
Expand Down
Loading

0 comments on commit 027b5cc

Please sign in to comment.