Skip to content

Commit a3c68e5

Browse files
authored
Merge pull request #672 from kbss-cvut/development
[4.1.0] Release
2 parents 448f4a0 + ebb9f53 commit a3c68e5

File tree

119 files changed

+3976
-2086
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

119 files changed

+3976
-2086
lines changed

NEWS.cs.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
#### Version 4.1.0
2+
3+
- Přidána podpora pro specifikaci primárního jazyka slovníku.
4+
- Přidána podpora pro vlastní (uživateli definované) atributy.
5+
- Přidána možnost zobrazit pojmy v selektorech jako prostý list.
6+
- Přidána možnost vybrat jazyk při fulltextovém vyhledávání.
7+
18
#### Verze 4.0.1
29

310
- Opravena chyba, při které mizely soubory po přidání nového souboru.

NEWS.en.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
#### Version 4.1.0
2+
3+
- Added support for setting primary language on vocabulary level.
4+
- Added support for custom user-defined attributes.
5+
- Support displaying terms in selectors as a flat list instead of a tree.
6+
- Support selecting language in fulltext search.
7+
18
#### Version 4.0.1
29

310
- Fix an issue with document files disappearing after a new file is added.

package-lock.json

Lines changed: 716 additions & 515 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "termit-ui",
3-
"version": "4.0.1",
3+
"version": "4.1.0",
44
"private": true,
55
"homepage": ".",
66
"license": "GPL-3.0-only",
@@ -10,14 +10,14 @@
1010
"@fortawesome/fontawesome-free": "^6.6.0",
1111
"@opendata-mvcr/assembly-line-shared": "^0.3.2",
1212
"apexcharts": "^4.4.0",
13-
"axios": "^1.8.3",
13+
"axios": "^1.12.2",
1414
"classnames": "^2.5.1",
1515
"dom-serializer": "^1.3.2",
1616
"domhandler": "^4.3.1",
1717
"easymde": "2.18.0",
1818
"html-to-react": "1.5.0",
1919
"htmlparser2": "^4.1.0",
20-
"intelligent-tree-select": "0.11.8",
20+
"intelligent-tree-select": "0.12.3",
2121
"iso-639-1": "^2.1.15",
2222
"javascript-time-ago": "2.5.11",
2323
"js-cookie": "^3.0.5",
@@ -59,6 +59,7 @@
5959
"simple-xpath-position": "^2.0.2",
6060
"use-debounce": "^10.0.4",
6161
"uuid": "^10.0.0",
62+
"validate.io-uri": "1.0.0",
6263
"whatwg-fetch": "3.6.2",
6364
"whatwg-mimetype": "3.0.0"
6465
},
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
declare module "validate.io-uri" {
2+
export default function validateUri(uri?: string): boolean;
3+
}

src/action/ActionType.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export interface ExecuteQueryAction extends AsyncAction {
4949
}
5050
export interface SearchAction extends Action {
5151
searchString: string;
52+
language?: string;
5253
}
5354

5455
export interface SearchResultAction extends Action {
@@ -87,6 +88,10 @@ export interface UpdateAssetAction extends Action {
8788
iri: string;
8889
}
8990

91+
export interface SetTermsFlatListAction extends Action {
92+
flatList: boolean;
93+
}
94+
9095
enum ActionType {
9196
FETCH_USER = "FETCH_USER",
9297
LOGIN = "LOGIN",
@@ -143,6 +148,7 @@ enum ActionType {
143148
LOAD_DEFINITION_RELATED_TERMS_OF = "LOAD_DEFINITION_RELATED_TERMS_OF",
144149
REMOVE_VOCABULARY_TERM = "REMOVE_VOCABULARY_TERM",
145150
SET_TERM_STATE = "SET_TERM_STATE",
151+
SET_TERM_FLAT_LIST = "SET_TERM_FLAT_LIST",
146152

147153
CREATE_TERM_OCCURRENCE = "CREATE_TERM_OCCURRENCE",
148154
UPDATE_TERM_OCCURRENCE = "UPDATE_TERM_OCCURRENCE",
@@ -198,6 +204,9 @@ enum ActionType {
198204
GET_PROPERTIES = "GET_PROPERTIES",
199205
CREATE_PROPERTY = "CREATE_PROPERTY",
200206
CLEAR_PROPERTIES = "CLEAR_PROPERTIES",
207+
GET_CUSTOM_ATTRIBUTES = "GET_CUSTOM_ATTRIBUTES",
208+
CREATE_CUSTOM_ATTRIBUTE = "CREATE_CUSTOM_ATTRIBUTE",
209+
UPDATE_CUSTOM_ATTRIBUTE = "UPDATE_CUSTOM_ATTRIBUTE",
201210

202211
EXPORT_GLOSSARY = "EXPORT_GLOSSARY",
203212

@@ -258,6 +267,7 @@ enum ActionType {
258267
DOES_USERNAME_EXISTS = "DOES_USERNAME_EXISTS",
259268
LONG_RUNNING_TASKS_UPDATE = "LONG_RUNNING_TASKS_UPDATE",
260269
CLEAR_LONG_RUNNING_TASKS_QUEUE = "CLEAR_LONG_RUNNING_TASKS_QUEUE",
270+
RELOAD_FTS = "RELOAD_FTS",
261271
}
262272

263273
export default ActionType;

src/action/AsyncActions.ts

Lines changed: 114 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ import ActionType, {
4040
import Resource, { ResourceData } from "../model/Resource";
4141
import RdfsResource, {
4242
CONTEXT as RDFS_RESOURCE_CONTEXT,
43+
RdfProperty,
44+
RdfPropertyData,
4345
RdfsResourceData,
4446
} from "../model/RdfsResource";
4547
import TermItState from "../model/TermItState";
@@ -518,6 +520,7 @@ export function loadAllTerms(
518520
{
519521
searchString: fetchOptions.searchString,
520522
includeTerms: fetchOptions.includeTerms,
523+
flat: fetchOptions.flatList,
521524
namespace,
522525
},
523526
fetchOptions
@@ -535,6 +538,7 @@ export function loadTerms(
535538
searchString: fetchOptions.searchString,
536539
includeImported: fetchOptions.includeImported,
537540
includeTerms: fetchOptions.includeTerms,
541+
flat: fetchOptions.flatList,
538542
namespace: vocabularyIri.namespace,
539543
},
540544
fetchOptions
@@ -552,10 +556,10 @@ export function genericLoadTerms(
552556
dispatch(asyncActionRequest(action, true));
553557
let url = `${getApiPrefix(getState())}${prefix}/terms`;
554558
if (fetchOptions.optionID) {
555-
const parentIri = VocabularyUtils.create(fetchOptions.optionID);
559+
const parentIri = VocabularyUtils.create(fetchOptions.optionID as string);
556560
url = `${getApiPrefix(getState())}/terms/${parentIri.fragment}/subterms`;
557561
target.namespace = parentIri.namespace;
558-
} else if (!fetchOptions.searchString) {
562+
} else if (!fetchOptions.searchString && !fetchOptions.flatList) {
559563
url += "/roots";
560564
}
561565
return Ajax.get(
@@ -651,6 +655,7 @@ export function loadTermByIri(
651655
});
652656
};
653657
}
658+
654659
export function loadTypes() {
655660
const action = {
656661
type: ActionType.LOAD_TYPES,
@@ -1058,25 +1063,34 @@ export function getProperties() {
10581063
const action = {
10591064
type: ActionType.GET_PROPERTIES,
10601065
};
1066+
return getPropertiesImpl<RdfsResourceData, RdfsResource>(
1067+
action,
1068+
"/data/properties",
1069+
(d) => new RdfsResource(d),
1070+
(state) => state.properties
1071+
);
1072+
}
1073+
1074+
function getPropertiesImpl<T extends RdfsResourceData, E extends RdfsResource>(
1075+
action: Action,
1076+
endpoint: string,
1077+
mapper: (data: T) => E,
1078+
selector: (state: TermItState) => Array<E>
1079+
) {
10611080
return (dispatch: ThunkDispatch, getState: () => TermItState) => {
1062-
if (getState().properties.length > 0) {
1081+
if (selector(getState()).length > 0) {
10631082
return;
10641083
}
10651084
dispatch(asyncActionRequest(action, true));
1066-
return Ajax.get(Constants.API_PREFIX + "/data/properties")
1085+
return Ajax.get(Constants.API_PREFIX + endpoint)
10671086
.then((data: object[]) =>
1068-
JsonLdUtils.compactAndResolveReferencesAsArray<RdfsResourceData>(
1087+
JsonLdUtils.compactAndResolveReferencesAsArray<T>(
10691088
data,
10701089
RDFS_RESOURCE_CONTEXT
10711090
)
10721091
)
1073-
.then((data: RdfsResourceData[]) =>
1074-
dispatch(
1075-
asyncActionSuccessWithPayload(
1076-
action,
1077-
data.map((d) => new RdfsResource(d))
1078-
)
1079-
)
1092+
.then((data: T[]) =>
1093+
dispatch(asyncActionSuccessWithPayload(action, data.map(mapper)))
10801094
)
10811095
.catch((error: ErrorData) => dispatch(asyncActionFailure(action, error)));
10821096
};
@@ -1086,13 +1100,76 @@ export function createProperty(property: RdfsResource) {
10861100
const action = {
10871101
type: ActionType.CREATE_PROPERTY,
10881102
};
1103+
return createPropertyImpl(property, action, "/data/properties");
1104+
}
1105+
1106+
function createPropertyImpl(
1107+
property: { toJsonLd: () => object },
1108+
action: Action,
1109+
endpoint: string
1110+
) {
10891111
return (dispatch: ThunkDispatch) => {
10901112
dispatch(asyncActionRequest(action, true));
10911113
return Ajax.post(
1092-
Constants.API_PREFIX + "/data/properties",
1114+
Constants.API_PREFIX + endpoint,
10931115
content(property.toJsonLd())
10941116
)
1095-
.then(() => dispatch(asyncActionSuccess(action)))
1117+
.then(() => {
1118+
dispatch(asyncActionSuccess(action));
1119+
dispatch(
1120+
publishMessage(
1121+
new Message(
1122+
{ messageId: "properties.edit.new.success" },
1123+
MessageType.SUCCESS
1124+
)
1125+
)
1126+
);
1127+
})
1128+
.catch((error: ErrorData) => dispatch(asyncActionFailure(action, error)));
1129+
};
1130+
}
1131+
1132+
export function getCustomAttributes() {
1133+
return getPropertiesImpl<RdfPropertyData, RdfProperty>(
1134+
{ type: ActionType.GET_CUSTOM_ATTRIBUTES },
1135+
"/data/custom-attributes",
1136+
(d) => new RdfProperty(d),
1137+
() => []
1138+
);
1139+
}
1140+
1141+
export function createCustomAttribute(attribute: RdfProperty) {
1142+
return createPropertyImpl(
1143+
attribute,
1144+
{ type: ActionType.CREATE_CUSTOM_ATTRIBUTE },
1145+
"/data/custom-attributes"
1146+
);
1147+
}
1148+
1149+
export function updateCustomAttribute(attribute: RdfProperty) {
1150+
const action = { type: ActionType.UPDATE_CUSTOM_ATTRIBUTE };
1151+
return (dispatch: ThunkDispatch) => {
1152+
dispatch(asyncActionRequest(action, true));
1153+
return Ajax.put(
1154+
Constants.API_PREFIX +
1155+
"/data/custom-attributes/" +
1156+
VocabularyUtils.create(attribute.iri).fragment,
1157+
content(attribute.toJsonLd())
1158+
)
1159+
.then(() => {
1160+
dispatch(asyncActionSuccess(action));
1161+
dispatch(
1162+
publishMessage(
1163+
new Message(
1164+
{
1165+
messageId:
1166+
"administration.customization.customAttributes.update.success",
1167+
},
1168+
MessageType.SUCCESS
1169+
)
1170+
)
1171+
);
1172+
})
10961173
.catch((error: ErrorData) => dispatch(asyncActionFailure(action, error)));
10971174
};
10981175
}
@@ -1249,6 +1326,28 @@ export function clearLongRunningTasksQueue() {
12491326
};
12501327
}
12511328

1329+
export function reloadFullTextSearch() {
1330+
const action = { type: ActionType.RELOAD_FTS };
1331+
return (dispatch: ThunkDispatch) => {
1332+
dispatch(asyncActionRequest(action));
1333+
return Ajax.post(`${Constants.API_PREFIX}/admin/reload-fts`)
1334+
.then(() => dispatch(asyncActionSuccess(action)))
1335+
.then(() =>
1336+
dispatch(
1337+
publishMessage(
1338+
new Message(
1339+
{
1340+
messageId: "administration.maintenance.reloadFTS.success",
1341+
},
1342+
MessageType.SUCCESS
1343+
)
1344+
)
1345+
)
1346+
)
1347+
.catch((error) => dispatch(asyncActionFailure(action, error)));
1348+
};
1349+
}
1350+
12521351
export function loadConfiguration() {
12531352
const action = { type: ActionType.LOAD_CONFIGURATION };
12541353
return (dispatch: ThunkDispatch) => {
@@ -1267,6 +1366,7 @@ export function loadConfiguration() {
12671366
data.roles = Utils.sanitizeArray(data.roles).map(
12681367
(d: UserRoleData) => new UserRole(d)
12691368
);
1369+
data.indexedLanguages = Utils.sanitizeArray(data.indexedLanguages);
12701370
return dispatch(asyncActionSuccessWithPayload(action, data));
12711371
})
12721372
.catch((error) => dispatch(asyncActionFailure(action, error)));

src/action/SearchActions.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,12 @@ let updateSearchTimer: ReturnType<typeof setTimeout> | null = null;
6060
/**
6161
* Change the search criteria and trigger a new search.
6262
*/
63-
export function updateSearchFilter(searchString: string) {
63+
export function updateSearchFilter(searchString: string, language: string) {
6464
return (dispatch: ThunkDispatch, getState: () => TermItState) => {
6565
dispatch({
6666
type: ActionType.UPDATE_SEARCH_FILTER,
6767
searchString,
68+
language,
6869
});
6970

7071
// Clear search results
@@ -99,7 +100,9 @@ export function searchEverything() {
99100
dispatch({ type: ActionType.SEARCH_START });
100101
const state: TermItState = getState();
101102
if (state.searchListenerCount > 0 && !state.searchQuery.isEmpty()) {
102-
return dispatch(search(state.searchQuery.searchQuery, true));
103+
return dispatch(
104+
search(state.searchQuery.searchQuery, state.searchQuery.language, true)
105+
);
103106
} else {
104107
dispatch({ type: ActionType.SEARCH_FINISH });
105108
return Promise.resolve();
@@ -114,15 +117,20 @@ export function searchEverything() {
114117
*/
115118
let latestSearch: Promise<any>;
116119

117-
export function search(searchString: string, disableLoading: boolean = true) {
120+
export function search(
121+
searchString: string,
122+
language: string,
123+
disableLoading: boolean = true
124+
) {
118125
const action = {
119126
type: ActionType.SEARCH,
120127
};
121128
return (dispatch: ThunkDispatch) => {
122129
dispatch(SyncActions.asyncActionRequest(action, disableLoading));
130+
console.debug(searchString, language, disableLoading);
123131
const promiseToReturn = Ajax.get(
124132
Constants.API_PREFIX + "/search/fts",
125-
params({ searchString })
133+
params({ searchString, language })
126134
)
127135
.then((data: object) =>
128136
JsonLdUtils.compactAndResolveReferencesAsArray<SearchResultData>(

src/action/SyncActions.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ActionType, {
77
MessageAction,
88
NotificationAction,
99
SelectingTermsAction,
10+
SetTermsFlatListAction,
1011
SwitchLanguageAction,
1112
UpdateLastModifiedAction,
1213
} from "./ActionType";
@@ -23,6 +24,7 @@ import {
2324
AnnotationClass,
2425
AnnotationOrigin,
2526
} from "../model/AnnotatorLegendFilter";
27+
import { saveTermsFlatListPreference } from "src/util/UISettingsUtil";
2628

2729
export function asyncActionRequest(
2830
a: Action,
@@ -213,3 +215,11 @@ export function setAnnotatorLegendFilter(
213215
enabled,
214216
};
215217
}
218+
219+
export function setTermsFlatList(flatList: boolean): SetTermsFlatListAction {
220+
saveTermsFlatListPreference(flatList);
221+
return {
222+
type: ActionType.SET_TERM_FLAT_LIST,
223+
flatList,
224+
};
225+
}

src/component/MainView.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191

9292
.nav-search {
9393
flex-grow: 1;
94-
max-width: 30rem;
94+
max-width: 40rem;
9595
}
9696

9797
.navbar {

0 commit comments

Comments
 (0)