Add support for multiple sources on dataset autocomplete templates
This commit is contained in:
parent
33ec8b81c0
commit
2b9c2ee1e7
|
@ -37,6 +37,7 @@ import javax.xml.xpath.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@ -46,12 +47,14 @@ public class DatasetProfileManager {
|
||||||
private ApiContext apiContext;
|
private ApiContext apiContext;
|
||||||
private DatabaseRepository databaseRepository;
|
private DatabaseRepository databaseRepository;
|
||||||
private Environment environment;
|
private Environment environment;
|
||||||
|
private List<String> cache;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public DatasetProfileManager(ApiContext apiContext, Environment environment) {
|
public DatasetProfileManager(ApiContext apiContext, Environment environment) {
|
||||||
this.apiContext = apiContext;
|
this.apiContext = apiContext;
|
||||||
this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository();
|
this.databaseRepository = apiContext.getOperationsContext().getDatabaseRepository();
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
|
this.cache = new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public eu.eudat.models.data.admin.composite.DatasetProfile getDatasetProfile(String id) {
|
public eu.eudat.models.data.admin.composite.DatasetProfile getDatasetProfile(String id) {
|
||||||
|
@ -107,17 +110,45 @@ public class DatasetProfileManager {
|
||||||
List<ExternalAutocompleteFieldModel> result = new LinkedList<>();
|
List<ExternalAutocompleteFieldModel> result = new LinkedList<>();
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.setAccept(Collections.singletonList(MediaType.valueOf("application/vnd.api+json; charset=utf-8")));
|
DocumentContext jsonContext = null;
|
||||||
headers.setContentType(MediaType.APPLICATION_JSON);
|
HttpEntity<String> entity;
|
||||||
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
|
ResponseEntity response;
|
||||||
|
List<Map<String, String>> jsonItems;
|
||||||
|
int i = 0;
|
||||||
|
for (AutoCompleteData.AutoCompleteSingleData singleData: data.getAutoCompleteSingleDataList()) {
|
||||||
|
switch (AutoCompleteData.AutocompleteType.fromValue(singleData.getAutocompleteType())) {
|
||||||
|
case UNCACHED:
|
||||||
|
headers.setAccept(Collections.singletonList(MediaType.valueOf("application/vnd.api+json; charset=utf-8")));
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
entity = new HttpEntity<>("parameters", headers);
|
||||||
|
|
||||||
ResponseEntity<Object> response = restTemplate.exchange(data.getUrl() + "?search=" + like, HttpMethod.GET, entity, Object.class);
|
response = restTemplate.exchange(singleData.getUrl() + "?search=" + like, HttpMethod.GET, entity, Object.class);
|
||||||
DocumentContext jsonContext = JsonPath.parse(response.getBody());
|
jsonContext = JsonPath.parse(response.getBody());
|
||||||
|
jsonItems = jsonContext.read(singleData.getOptionsRoot() + "['" + singleData.getAutoCompleteOptions().getLabel() + "','" + singleData.getAutoCompleteOptions().getValue() + "','" + singleData.getAutoCompleteOptions().getSource() + "','" + "uri" + "']");
|
||||||
|
jsonItems.forEach(item -> result.add(new ExternalAutocompleteFieldModel(item.get(singleData.getAutoCompleteOptions().getValue()), item.get(singleData.getAutoCompleteOptions().getLabel()), item.get(singleData.getAutoCompleteOptions().getSource()), item.get("uri"))));
|
||||||
|
break;
|
||||||
|
case CACHED:
|
||||||
|
headers.setAccept(Collections.singletonList(MediaType.valueOf("text/plain; charset=utf-8")));
|
||||||
|
headers.setContentType(MediaType.TEXT_PLAIN);
|
||||||
|
entity = new HttpEntity<>("parameters", headers);
|
||||||
|
|
||||||
List<Map<String, String>> jsonItems = jsonContext.read(data.getOptionsRoot() + "['" + data.getAutoCompleteOptions().getLabel() + "','" + data.getAutoCompleteOptions().getValue() + "','" + data.getAutoCompleteOptions().getSource() + "','" + "uri" + "']");
|
if (this.cache.size() <= i) {
|
||||||
jsonItems.forEach(item -> result.add(new ExternalAutocompleteFieldModel(item.get(data.getAutoCompleteOptions().getValue()), item.get(data.getAutoCompleteOptions().getLabel()), item.get(data.getAutoCompleteOptions().getSource()), item.get("uri"))));
|
response = restTemplate.exchange(singleData.getUrl(), HttpMethod.GET, entity, String.class);
|
||||||
|
this.cache.add((String) response.getBody());
|
||||||
|
}
|
||||||
|
jsonContext = JsonPath.parse(cache.get(i));
|
||||||
|
jsonItems = jsonContext.read(singleData.getOptionsRoot() + "['" + singleData.getAutoCompleteOptions().getLabel() + "','" + singleData.getAutoCompleteOptions().getValue() + "','" + singleData.getAutoCompleteOptions().getSource() + "','" + "uri" + "']");
|
||||||
|
jsonItems.stream().filter(item -> item.get(singleData.getAutoCompleteOptions().getLabel()).toLowerCase().contains(like.toLowerCase()))
|
||||||
|
.forEach(item -> result.add(new ExternalAutocompleteFieldModel(item.get(singleData.getAutoCompleteOptions().getValue()), item.get(singleData.getAutoCompleteOptions().getLabel()), item.get(singleData.getAutoCompleteOptions().getSource()) != null ? item.get(singleData.getAutoCompleteOptions().getSource()) : singleData.getAutoCompleteOptions().getSource(), item.get("uri"))));
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
}
|
||||||
|
|
||||||
|
return result.stream().sorted(Comparator.comparing(ExternalAutocompleteFieldModel::getLabel)).collect(Collectors.toList());
|
||||||
|
|
||||||
|
//return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseEntity<byte[]> getDocument(eu.eudat.models.data.user.composite.DatasetProfile datasetProfile, String label) throws IllegalAccessException, IOException, InstantiationException {
|
public ResponseEntity<byte[]> getDocument(eu.eudat.models.data.user.composite.DatasetProfile datasetProfile, String label) throws IllegalAccessException, IOException, InstantiationException {
|
||||||
|
|
|
@ -217,13 +217,17 @@ public class ExportXmlBuilderDatasetProfile {
|
||||||
AutoCompleteData autoCompleteDataObject = (AutoCompleteData) field.getData();
|
AutoCompleteData autoCompleteDataObject = (AutoCompleteData) field.getData();
|
||||||
dataOut.setAttribute("label", autoCompleteDataObject.getLabel());
|
dataOut.setAttribute("label", autoCompleteDataObject.getLabel());
|
||||||
dataOut.setAttribute("type", autoCompleteDataObject.getType());
|
dataOut.setAttribute("type", autoCompleteDataObject.getType());
|
||||||
dataOut.setAttribute("optionsRoot", autoCompleteDataObject.getOptionsRoot());
|
for (AutoCompleteData.AutoCompleteSingleData singleData: autoCompleteDataObject.getAutoCompleteSingleDataList()) {
|
||||||
dataOut.setAttribute("url", autoCompleteDataObject.getUrl());
|
Element singleItem = element.createElement("autocompleteSingle");
|
||||||
if (autoCompleteDataObject.getAutoCompleteOptions() != null) {
|
singleItem.setAttribute("optionsRoot", singleData.getOptionsRoot());
|
||||||
Element optionChild = element.createElement("option");
|
singleItem.setAttribute("url", singleData.getUrl());
|
||||||
optionChild.setAttribute("label", autoCompleteDataObject.getAutoCompleteOptions().getLabel());
|
if (singleData.getAutoCompleteOptions() != null) {
|
||||||
optionChild.setAttribute("value", autoCompleteDataObject.getAutoCompleteOptions().getValue());
|
Element optionChild = element.createElement("option");
|
||||||
dataOut.appendChild(optionChild);
|
optionChild.setAttribute("label", singleData.getAutoCompleteOptions().getLabel());
|
||||||
|
optionChild.setAttribute("value", singleData.getAutoCompleteOptions().getValue());
|
||||||
|
singleItem.appendChild(optionChild);
|
||||||
|
}
|
||||||
|
dataOut.appendChild(singleItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (field.getViewStyle().getRenderStyle().equals("booleanDecision")) {
|
} else if (field.getViewStyle().getRenderStyle().equals("booleanDecision")) {
|
||||||
|
|
|
@ -2,87 +2,156 @@ package eu.eudat.models.data.components.commons.datafield;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class AutoCompleteData extends ComboBoxData<AutoCompleteData> {
|
public class AutoCompleteData extends ComboBoxData<AutoCompleteData> {
|
||||||
private String url;
|
public class AutoCompleteSingleData {
|
||||||
private Option autoCompleteOptions;
|
private int autocompleteType;
|
||||||
private String optionsRoot;
|
private String url;
|
||||||
|
private Option autoCompleteOptions;
|
||||||
|
private String optionsRoot;
|
||||||
|
|
||||||
|
public int getAutocompleteType() {
|
||||||
|
return autocompleteType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutocompleteType(int autocompleteType) {
|
||||||
|
this.autocompleteType = autocompleteType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOptionsRoot() {
|
||||||
|
return optionsRoot;
|
||||||
|
}
|
||||||
|
public void setOptionsRoot(String optionsRoot) {
|
||||||
|
this.optionsRoot = optionsRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
public void setUrl(String url) {
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Option getAutoCompleteOptions() {
|
||||||
|
return autoCompleteOptions;
|
||||||
|
}
|
||||||
|
public void setAutoCompleteOptions(Option autoCompleteOptions) {
|
||||||
|
this.autoCompleteOptions = autoCompleteOptions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Boolean multiAutoComplete;
|
private Boolean multiAutoComplete;
|
||||||
|
private List<AutoCompleteSingleData> autoCompleteSingleDataList;
|
||||||
public String getOptionsRoot() {
|
|
||||||
return optionsRoot;
|
|
||||||
}
|
|
||||||
public void setOptionsRoot(String optionsRoot) {
|
|
||||||
this.optionsRoot = optionsRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUrl() {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
public void setUrl(String url) {
|
|
||||||
this.url = url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option getAutoCompleteOptions() {
|
|
||||||
return autoCompleteOptions;
|
|
||||||
}
|
|
||||||
public void setAutoCompleteOptions(Option autoCompleteOptions) {
|
|
||||||
this.autoCompleteOptions = autoCompleteOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Boolean getMultiAutoComplete() { return multiAutoComplete; }
|
public Boolean getMultiAutoComplete() { return multiAutoComplete; }
|
||||||
public void setMultiAutoComplete(Boolean multiAutoComplete) { this.multiAutoComplete = multiAutoComplete; }
|
public void setMultiAutoComplete(Boolean multiAutoComplete) { this.multiAutoComplete = multiAutoComplete; }
|
||||||
|
|
||||||
|
public List<AutoCompleteSingleData> getAutoCompleteSingleDataList() {
|
||||||
|
return autoCompleteSingleDataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoCompleteSingleDataList(List<AutoCompleteSingleData> autoCompleteSingleDataList) {
|
||||||
|
this.autoCompleteSingleDataList = autoCompleteSingleDataList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Element toXml(Document doc) {
|
public Element toXml(Document doc) {
|
||||||
Element root = super.toXml(doc);
|
Element root = super.toXml(doc);
|
||||||
|
|
||||||
root.setAttribute("url", this.url);
|
|
||||||
root.setAttribute("optionsRoot", this.optionsRoot);
|
|
||||||
if (this.multiAutoComplete != null)
|
if (this.multiAutoComplete != null)
|
||||||
root.setAttribute("multiAutoComplete", this.multiAutoComplete.toString());
|
root.setAttribute("multiAutoComplete", this.multiAutoComplete.toString());
|
||||||
Element element = doc.createElement("option");
|
for (AutoCompleteSingleData singleData: this.autoCompleteSingleDataList) {
|
||||||
element.setAttribute("label", this.autoCompleteOptions.getLabel());
|
Element parent = doc.createElement("autocompleteSingle");
|
||||||
element.setAttribute("value", autoCompleteOptions.getValue());
|
parent.setAttribute("url", singleData.url);
|
||||||
element.setAttribute("source", autoCompleteOptions.getSource());
|
parent.setAttribute("optionsRoot", singleData.optionsRoot);
|
||||||
root.appendChild(element);
|
parent.setAttribute("autoCompleteType", Integer.toString(singleData.autocompleteType));
|
||||||
|
Element element = doc.createElement("option");
|
||||||
|
element.setAttribute("label", singleData.autoCompleteOptions.getLabel());
|
||||||
|
element.setAttribute("value", singleData.autoCompleteOptions.getValue());
|
||||||
|
element.setAttribute("source", singleData.autoCompleteOptions.getSource());
|
||||||
|
parent.appendChild(element);
|
||||||
|
root.appendChild(parent);
|
||||||
|
}
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AutoCompleteData fromXml(Element item) {
|
public AutoCompleteData fromXml(Element item) {
|
||||||
super.fromXml(item);
|
super.fromXml(item);
|
||||||
this.url = item.getAttribute("url");
|
this.autoCompleteSingleDataList = new ArrayList<>();
|
||||||
this.optionsRoot = item.getAttribute("optionsRoot");
|
NodeList items = item.getElementsByTagName("autocompleteSingle");
|
||||||
|
if (items != null && items.getLength() > 0) {
|
||||||
|
for (int i = 0; i < items.getLength(); i++) {
|
||||||
|
this.autoCompleteSingleDataList.add(new AutoCompleteSingleData());
|
||||||
|
Element single = (Element) items.item(i);
|
||||||
|
this.mapFromXml(single, this.autoCompleteSingleDataList.get(i));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.autoCompleteSingleDataList.add(new AutoCompleteSingleData());
|
||||||
|
this.mapFromXml(item, this.autoCompleteSingleDataList.get(0));
|
||||||
|
}
|
||||||
this.multiAutoComplete = Boolean.parseBoolean(item.getAttribute("multiAutoComplete"));
|
this.multiAutoComplete = Boolean.parseBoolean(item.getAttribute("multiAutoComplete"));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mapFromXml(Element item, AutoCompleteSingleData singleData) {
|
||||||
|
singleData.url = item.getAttribute("url");
|
||||||
|
singleData.optionsRoot = item.getAttribute("optionsRoot");
|
||||||
|
this.multiAutoComplete = Boolean.parseBoolean(item.getAttribute("multiAutoComplete"));
|
||||||
|
if (item.getAttribute("autoCompleteType") == null || item.getAttribute("autoCompleteType").equals("") ) {
|
||||||
|
singleData.autocompleteType = AutocompleteType.UNCACHED.getValue();
|
||||||
|
} else {
|
||||||
|
singleData.autocompleteType = AutocompleteType.fromValue(Integer.parseInt(item.getAttribute("autoCompleteType"))).getValue();
|
||||||
|
}
|
||||||
Element optionElement = (Element) item.getElementsByTagName("option").item(0);
|
Element optionElement = (Element) item.getElementsByTagName("option").item(0);
|
||||||
if (optionElement != null) {
|
if (optionElement != null) {
|
||||||
this.autoCompleteOptions = new Option();
|
singleData.autoCompleteOptions = new Option();
|
||||||
this.autoCompleteOptions.setLabel(optionElement.getAttribute("label"));
|
singleData.autoCompleteOptions.setLabel(optionElement.getAttribute("label"));
|
||||||
this.autoCompleteOptions.setValue(optionElement.getAttribute("value"));
|
singleData.autoCompleteOptions.setValue(optionElement.getAttribute("value"));
|
||||||
this.autoCompleteOptions.setSource(optionElement.getAttribute("source"));
|
singleData.autoCompleteOptions.setSource(optionElement.getAttribute("source"));
|
||||||
this.autoCompleteOptions.setUri(optionElement.getAttribute("uri"));
|
singleData.autoCompleteOptions.setUri(optionElement.getAttribute("uri"));
|
||||||
}
|
}
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AutoCompleteData fromData(Object data) {
|
public AutoCompleteData fromData(Object data) {
|
||||||
super.fromData(data);
|
super.fromData(data);
|
||||||
this.autoCompleteOptions = new Option();
|
this.autoCompleteSingleDataList = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
this.url = (String) ((Map<String, Object>) data).get("url");
|
|
||||||
this.optionsRoot = (String) ((Map<String, Object>) data).get("optionsRoot");
|
|
||||||
this.multiAutoComplete = (Boolean) ((Map<Boolean, Object>) data).get("multiAutoComplete");
|
this.multiAutoComplete = (Boolean) ((Map<Boolean, Object>) data).get("multiAutoComplete");
|
||||||
Map<String, String> options = ((Map<String, Map<String, String>>) data).get("autoCompleteOptions");
|
|
||||||
if (options != null) {
|
List<Map<String, Object>> dataList = (List<Map<String, Object>>) ((Map<String, Object>) data).get("autoCompleteSingleDataList");
|
||||||
this.autoCompleteOptions.setLabel(options.get("label"));
|
|
||||||
this.autoCompleteOptions.setValue(options.get("value"));
|
this.autoCompleteSingleDataList = new ArrayList<>();
|
||||||
this.autoCompleteOptions.setSource(options.get("source"));
|
|
||||||
this.autoCompleteOptions.setUri(options.get("uri"));
|
int i = 0;
|
||||||
|
for (Map<String, Object> singleData: dataList) {
|
||||||
|
this.autoCompleteSingleDataList.add(new AutoCompleteSingleData());
|
||||||
|
this.autoCompleteSingleDataList.get(i).autoCompleteOptions = new Option();
|
||||||
|
this.autoCompleteSingleDataList.get(i).url = (String) singleData.get("url");
|
||||||
|
this.autoCompleteSingleDataList.get(i).optionsRoot = (String) singleData.get("optionsRoot");
|
||||||
|
|
||||||
|
if (singleData.get("autoCompleteType") == null) {
|
||||||
|
this.autoCompleteSingleDataList.get(i).autocompleteType = AutocompleteType.UNCACHED.getValue();
|
||||||
|
} else {
|
||||||
|
this.autoCompleteSingleDataList.get(i).autocompleteType = AutocompleteType.fromValue((Integer) singleData.get("autoCompleteType")).getValue();
|
||||||
|
}
|
||||||
|
Map<String, String> options = (Map<String, String>) singleData.get("autoCompleteOptions");
|
||||||
|
if (options != null) {
|
||||||
|
this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setLabel(options.get("label"));
|
||||||
|
this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setValue(options.get("value"));
|
||||||
|
this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setSource(options.get("source"));
|
||||||
|
this.autoCompleteSingleDataList.get(i).autoCompleteOptions.setUri(options.get("uri"));
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,4 +188,29 @@ public class AutoCompleteData extends ComboBoxData<AutoCompleteData> {
|
||||||
dataMap.put("source", item != null ? item.getAttribute("source") : "");
|
dataMap.put("source", item != null ? item.getAttribute("source") : "");
|
||||||
return dataMap;
|
return dataMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum AutocompleteType {
|
||||||
|
UNCACHED(0), CACHED(1);
|
||||||
|
|
||||||
|
int value;
|
||||||
|
|
||||||
|
AutocompleteType(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValue() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AutocompleteType fromValue(int value) {
|
||||||
|
for (AutocompleteType type: AutocompleteType.values()) {
|
||||||
|
if (type.getValue() == value) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UNCACHED;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,15 @@ export interface FieldData {
|
||||||
|
|
||||||
export interface AutoCompleteFieldData extends FieldData {
|
export interface AutoCompleteFieldData extends FieldData {
|
||||||
type: DatasetProfileComboBoxType;
|
type: DatasetProfileComboBoxType;
|
||||||
|
autoCompleteSingleDataList: AutoCompleteSingleData[];
|
||||||
|
multiAutoComplete: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AutoCompleteSingleData extends FieldData {
|
||||||
url: string;
|
url: string;
|
||||||
optionsRoot: string;
|
optionsRoot: string;
|
||||||
autoCompleteOptions: FieldDataOption;
|
autoCompleteOptions: FieldDataOption;
|
||||||
multiAutoComplete: boolean;
|
autocompleteType: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CheckBoxFieldData extends FieldData {
|
export interface CheckBoxFieldData extends FieldData {
|
||||||
|
@ -56,6 +61,7 @@ export interface ResearchersAutoCompleteFieldData extends FieldData {
|
||||||
export interface DatasetsAutoCompleteFieldData extends FieldData {
|
export interface DatasetsAutoCompleteFieldData extends FieldData {
|
||||||
type: DatasetProfileInternalDmpEntitiesType;
|
type: DatasetProfileInternalDmpEntitiesType;
|
||||||
multiAutoComplete: boolean;
|
multiAutoComplete: boolean;
|
||||||
|
autoCompleteType: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DmpsAutoCompleteFieldData extends FieldData {
|
export interface DmpsAutoCompleteFieldData extends FieldData {
|
||||||
|
|
|
@ -3,36 +3,40 @@ import { DatasetProfileComboBoxType } from '../../../../../core/common/enum/data
|
||||||
import { AutoCompleteFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
|
import { AutoCompleteFieldData } from '../../../../../core/model/dataset-profile-definition/field-data/field-data';
|
||||||
import { FieldDataEditorModel } from './field-data-editor-model';
|
import { FieldDataEditorModel } from './field-data-editor-model';
|
||||||
import { FieldDataOptionEditorModel } from './field-data-option-editor-model';
|
import { FieldDataOptionEditorModel } from './field-data-option-editor-model';
|
||||||
|
import { AutoCompleteSingleDataEditorModel } from './auto-complete-single-data';
|
||||||
|
|
||||||
export class AutoCompleteFieldDataEditorModel extends FieldDataEditorModel<AutoCompleteFieldDataEditorModel> {
|
export class AutoCompleteFieldDataEditorModel extends FieldDataEditorModel<AutoCompleteFieldDataEditorModel> {
|
||||||
|
|
||||||
public type: DatasetProfileComboBoxType = DatasetProfileComboBoxType.Autocomplete;
|
public type: DatasetProfileComboBoxType = DatasetProfileComboBoxType.Autocomplete;
|
||||||
public url: string;
|
|
||||||
public optionsRoot: string;
|
|
||||||
public multiAutoComplete: boolean;
|
public multiAutoComplete: boolean;
|
||||||
public autoCompleteOptions: FieldDataOptionEditorModel = new FieldDataOptionEditorModel();
|
public autoCompleteSingleDataList: Array<AutoCompleteSingleDataEditorModel> = new Array<AutoCompleteSingleDataEditorModel>();
|
||||||
//public multiAutoCompleteOptions: FieldDataOptionEditorModel = new FieldDataOptionEditorModel();
|
//public multiAutoCompleteOptions: FieldDataOptionEditorModel = new FieldDataOptionEditorModel();
|
||||||
|
|
||||||
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
|
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
|
||||||
const formGroup = this.formBuilder.group({
|
const formGroup = this.formBuilder.group({
|
||||||
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.label')) }],
|
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.label')) }],
|
||||||
type: [{ value: this.type, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.type')) }],
|
type: [{ value: this.type, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.type')) }],
|
||||||
url: [{ value: this.url, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.url')) }],
|
|
||||||
optionsRoot: [{ value: this.optionsRoot, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.optionsRoot')) }],
|
|
||||||
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.multiAutoComplete')) }]
|
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('AutoCompleteFieldDataEditorModel.multiAutoComplete')) }]
|
||||||
});
|
});
|
||||||
formGroup.addControl('autoCompleteOptions', this.autoCompleteOptions.buildForm(disabled, skipDisable));
|
|
||||||
|
const autocompleteFormArray = new Array<FormGroup>();
|
||||||
|
if (this.autoCompleteSingleDataList) {
|
||||||
|
this.autoCompleteSingleDataList.forEach(item => {
|
||||||
|
const form: FormGroup = item.buildForm(disabled, skipDisable);
|
||||||
|
autocompleteFormArray.push(form);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
formGroup.addControl('autoCompleteSingleDataList', this.formBuilder.array(autocompleteFormArray));
|
||||||
|
|
||||||
return formGroup;
|
return formGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
fromModel(item: AutoCompleteFieldData): AutoCompleteFieldDataEditorModel {
|
fromModel(item: AutoCompleteFieldData): AutoCompleteFieldDataEditorModel {
|
||||||
this.type = item.type;
|
this.type = item.type;
|
||||||
this.url = item.url;
|
|
||||||
this.label = item.label;
|
this.label = item.label;
|
||||||
this.optionsRoot = item.optionsRoot;
|
|
||||||
this.multiAutoComplete = item.multiAutoComplete;
|
this.multiAutoComplete = item.multiAutoComplete;
|
||||||
this.autoCompleteOptions = new FieldDataOptionEditorModel().fromModel(item.autoCompleteOptions);
|
if (item.autoCompleteSingleDataList) { this.autoCompleteSingleDataList = item.autoCompleteSingleDataList.map(x => new AutoCompleteSingleDataEditorModel().fromModel(x)); }
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { FieldDataEditorModel } from './field-data-editor-model';
|
||||||
|
import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type';
|
||||||
|
import { FieldDataOptionEditorModel } from './field-data-option-editor-model';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { AutoCompleteFieldData, AutoCompleteSingleData } from '@app/core/model/dataset-profile-definition/field-data/field-data';
|
||||||
|
|
||||||
|
export class AutoCompleteSingleDataEditorModel extends FieldDataEditorModel<AutoCompleteSingleDataEditorModel> {
|
||||||
|
|
||||||
|
public url: string;
|
||||||
|
public optionsRoot: string;
|
||||||
|
|
||||||
|
public autoCompleteOptions: FieldDataOptionEditorModel = new FieldDataOptionEditorModel();
|
||||||
|
public autoCompleteType: number;
|
||||||
|
//public multiAutoCompleteOptions: FieldDataOptionEditorModel = new FieldDataOptionEditorModel();
|
||||||
|
|
||||||
|
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
|
||||||
|
const formGroup = this.formBuilder.group({
|
||||||
|
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.label')) }],
|
||||||
|
url: [{ value: this.url, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.url')) }],
|
||||||
|
optionsRoot: [{ value: this.optionsRoot, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.optionsRoot')) }],
|
||||||
|
autoCompleteType: [{ value: this.autoCompleteType, disabled: (disabled && !skipDisable.includes('AutoCompleteSingleDataEditorModel.autoCompleteType')) }]
|
||||||
|
});
|
||||||
|
formGroup.addControl('autoCompleteOptions', this.autoCompleteOptions.buildForm(disabled, skipDisable));
|
||||||
|
|
||||||
|
return formGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
fromModel(item: AutoCompleteSingleData): AutoCompleteSingleDataEditorModel {
|
||||||
|
this.url = item.url;
|
||||||
|
this.label = item.label;
|
||||||
|
this.optionsRoot = item.optionsRoot;
|
||||||
|
this.autoCompleteType = item.autocompleteType;
|
||||||
|
this.autoCompleteOptions = new FieldDataOptionEditorModel().fromModel(item.autoCompleteOptions);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,12 +8,14 @@ export class DatasetsAutoCompleteFieldDataEditorModel extends FieldDataEditorMod
|
||||||
public type: DatasetProfileInternalDmpEntitiesType = DatasetProfileInternalDmpEntitiesType.Datasets;
|
public type: DatasetProfileInternalDmpEntitiesType = DatasetProfileInternalDmpEntitiesType.Datasets;
|
||||||
public multiAutoComplete: boolean = false;
|
public multiAutoComplete: boolean = false;
|
||||||
public autoCompleteOptions: FieldDataOptionEditorModel = new FieldDataOptionEditorModel();
|
public autoCompleteOptions: FieldDataOptionEditorModel = new FieldDataOptionEditorModel();
|
||||||
|
public autoCompleteType: number;
|
||||||
|
|
||||||
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
|
buildForm(disabled: boolean = false, skipDisable: Array<String> = []): FormGroup {
|
||||||
const formGroup = this.formBuilder.group({
|
const formGroup = this.formBuilder.group({
|
||||||
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DatasetsAutoCompleteFieldDataEditorModel.label')) }],
|
label: [{ value: this.label, disabled: (disabled && !skipDisable.includes('DatasetsAutoCompleteFieldDataEditorModel.label')) }],
|
||||||
type: [{ value: this.type, disabled: (disabled && !skipDisable.includes('DatasetsAutoCompleteFieldDataEditorModel.type')) }],
|
type: [{ value: this.type, disabled: (disabled && !skipDisable.includes('DatasetsAutoCompleteFieldDataEditorModel.type')) }],
|
||||||
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('DatasetsAutoCompleteFieldDataEditorModel.multiAutoComplete')) }]
|
multiAutoComplete: [{ value: this.multiAutoComplete, disabled: (disabled && !skipDisable.includes('DatasetsAutoCompleteFieldDataEditorModel.multiAutoComplete')) }],
|
||||||
|
autoCompleteType: [{ value: this.autoCompleteType, disabled: (disabled && !skipDisable.includes('DatasetsAutoCompleteFieldDataEditorModel.autoCompleteType')) }]
|
||||||
})
|
})
|
||||||
return formGroup;
|
return formGroup;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +24,7 @@ export class DatasetsAutoCompleteFieldDataEditorModel extends FieldDataEditorMod
|
||||||
this.label = item.label;
|
this.label = item.label;
|
||||||
this.type = item.type;
|
this.type = item.type;
|
||||||
this.multiAutoComplete = item.multiAutoComplete;
|
this.multiAutoComplete = item.multiAutoComplete;
|
||||||
|
this.autoCompleteType = item.autoCompleteType;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,20 +9,36 @@
|
||||||
<input matInput type="string" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-PLACEHOLDER' | translate}}"
|
<input matInput type="string" placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-PLACEHOLDER' | translate}}"
|
||||||
[formControl]="form.get('data').get('label')">
|
[formControl]="form.get('data').get('label')">
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="col-md-12">
|
|
||||||
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-URL' | translate}}" [formControl]="this.form.get('data').get('url')">
|
<h6 style="font-weight: bold" class="col-auto">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-SOURCE-TITLE' | translate}}</h6>
|
||||||
</mat-form-field>
|
<button mat-raised-button type="button" class="col-auto" (click)="addSource()">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-ADD_SOURCE' | translate}}</button>
|
||||||
<mat-form-field class="col-md-3">
|
</div>
|
||||||
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-OPTIONS-ROOT' | translate}}"
|
|
||||||
[formControl]="this.form.get('data').get('optionsRoot')">
|
<div *ngFor="let singleForm of multiForm.controls; let i = index" class="row">
|
||||||
</mat-form-field>
|
<mat-form-field class="col-12">
|
||||||
<mat-form-field class="col-md-3">
|
<mat-label>{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-TYPE' | translate}}</mat-label>
|
||||||
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-LABEL' | translate}}" [formControl]="this.form.get('data').get('autoCompleteOptions').get('label')">
|
<mat-select [formControl]="singleForm.get('autoCompleteType')">
|
||||||
</mat-form-field>
|
<mat-option [value]="0">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-TYPE-UNCACHED' | translate}}</mat-option>
|
||||||
<mat-form-field class="col-md-3">
|
<mat-option [value]="1">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-TYPE-CACHED' | translate}}</mat-option>
|
||||||
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-VALUE' | translate}}" [formControl]="this.form.get('data').get('autoCompleteOptions').get('value')">
|
</mat-select>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
<mat-form-field class="col-md-3">
|
|
||||||
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-SOURCE' | translate}}" [formControl]="this.form.get('data').get('autoCompleteOptions').get('source')">
|
<mat-form-field class="col-md-12">
|
||||||
</mat-form-field>
|
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-URL' | translate}}" [formControl]="this.singleForm.get('url')">
|
||||||
</div>
|
</mat-form-field>
|
||||||
|
<mat-form-field class="col-md-3">
|
||||||
|
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-OPTIONS-ROOT' | translate}}"
|
||||||
|
[formControl]="this.singleForm.get('optionsRoot')">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="col-md-3">
|
||||||
|
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-LABEL' | translate}}" [formControl]="this.singleForm.get('autoCompleteOptions').get('label')">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="col-md-3">
|
||||||
|
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-VALUE' | translate}}" [formControl]="this.singleForm.get('autoCompleteOptions').get('value')">
|
||||||
|
</mat-form-field>
|
||||||
|
<mat-form-field class="col-md-3">
|
||||||
|
<input matInput placeholder="{{'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.FIELDS.FIELD-AUTOCOMPLETE-SOURCE' | translate}}" [formControl]="this.singleForm.get('autoCompleteOptions').get('source')">
|
||||||
|
</mat-form-field>
|
||||||
|
<button mat-button type="button" (click)="removeSource(i)"><mat-icon>delete</mat-icon></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnInit } from '@angular/core';
|
||||||
import { FormGroup } from '@angular/forms';
|
import { FormGroup, FormArray, AbstractControl } from '@angular/forms';
|
||||||
import { DatasetProfileComboBoxType } from '../../../../../../../core/common/enum/dataset-profile-combo-box-type';
|
import { DatasetProfileComboBoxType } from '../../../../../../../core/common/enum/dataset-profile-combo-box-type';
|
||||||
import { AutoCompleteFieldDataEditorModel } from '../../../../admin/field-data/auto-complete-field-data-editor-model';
|
import { AutoCompleteFieldDataEditorModel } from '../../../../admin/field-data/auto-complete-field-data-editor-model';
|
||||||
|
import { AutoCompleteSingleDataEditorModel } from '@app/ui/admin/dataset-profile/admin/field-data/auto-complete-single-data';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dataset-profile-editor-auto-complete-field-component',
|
selector: 'app-dataset-profile-editor-auto-complete-field-component',
|
||||||
|
@ -12,8 +13,18 @@ export class DatasetProfileEditorAutoCompleteFieldComponent implements OnInit {
|
||||||
|
|
||||||
@Input() form: FormGroup;
|
@Input() form: FormGroup;
|
||||||
private data: AutoCompleteFieldDataEditorModel = new AutoCompleteFieldDataEditorModel();
|
private data: AutoCompleteFieldDataEditorModel = new AutoCompleteFieldDataEditorModel();
|
||||||
|
multiForm: AbstractControl;
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.multiForm = (<FormArray>this.form.get('data').get('autoCompleteSingleDataList'));
|
||||||
this.data.type = DatasetProfileComboBoxType.Autocomplete;
|
this.data.type = DatasetProfileComboBoxType.Autocomplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSource() {
|
||||||
|
(<FormArray>this.multiForm).push(new AutoCompleteSingleDataEditorModel().buildForm());
|
||||||
|
}
|
||||||
|
|
||||||
|
removeSource(index: number) {
|
||||||
|
(<FormArray>this.multiForm).removeAt(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -321,6 +321,11 @@
|
||||||
"FIELD-RADIO-BOX-VALUE": "Value",
|
"FIELD-RADIO-BOX-VALUE": "Value",
|
||||||
"FIELD-AUTOCOMPLETE-TITLE": "Autocomplete Data",
|
"FIELD-AUTOCOMPLETE-TITLE": "Autocomplete Data",
|
||||||
"FIELD-AUTOCOMPLETE-PLACEHOLDER": "Input Placeholder",
|
"FIELD-AUTOCOMPLETE-PLACEHOLDER": "Input Placeholder",
|
||||||
|
"FIELD-AUTOCOMPLETE-SOURCE-TITLE": "Sources",
|
||||||
|
"FIELD-AUTOCOMPLETE-ADD_SOURCE": "Add Source",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE": "Source Type",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE-UNCACHED": "Uncached",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE-CACHED": "Cached",
|
||||||
"FIELD-AUTOCOMPLETE-LABEL": "Label",
|
"FIELD-AUTOCOMPLETE-LABEL": "Label",
|
||||||
"FIELD-AUTOCOMPLETE-VALUE": "Value",
|
"FIELD-AUTOCOMPLETE-VALUE": "Value",
|
||||||
"FIELD-AUTOCOMPLETE-SOURCE": "Source",
|
"FIELD-AUTOCOMPLETE-SOURCE": "Source",
|
||||||
|
|
|
@ -321,6 +321,11 @@
|
||||||
"FIELD-RADIO-BOX-VALUE": "Valor",
|
"FIELD-RADIO-BOX-VALUE": "Valor",
|
||||||
"FIELD-AUTOCOMPLETE-TITLE": "Datos autocompletado",
|
"FIELD-AUTOCOMPLETE-TITLE": "Datos autocompletado",
|
||||||
"FIELD-AUTOCOMPLETE-PLACEHOLDER": "Marcador de entrada",
|
"FIELD-AUTOCOMPLETE-PLACEHOLDER": "Marcador de entrada",
|
||||||
|
"FIELD-AUTOCOMPLETE-SOURCE-TITLE": "Sources",
|
||||||
|
"FIELD-AUTOCOMPLETE-ADD_SOURCE": "Add Source",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE": "Source Type",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE-UNCACHED": "Uncached",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE-CACHED": "Cached",
|
||||||
"FIELD-AUTOCOMPLETE-LABEL": "Etiqueta",
|
"FIELD-AUTOCOMPLETE-LABEL": "Etiqueta",
|
||||||
"FIELD-AUTOCOMPLETE-VALUE": "Valor",
|
"FIELD-AUTOCOMPLETE-VALUE": "Valor",
|
||||||
"FIELD-AUTOCOMPLETE-SOURCE": "Fuente",
|
"FIELD-AUTOCOMPLETE-SOURCE": "Fuente",
|
||||||
|
|
|
@ -321,6 +321,11 @@
|
||||||
"FIELD-RADIO-BOX-VALUE": "Τιμή",
|
"FIELD-RADIO-BOX-VALUE": "Τιμή",
|
||||||
"FIELD-AUTOCOMPLETE-TITLE": "Αυτόματη Συμπλήρωση Δεδομένων",
|
"FIELD-AUTOCOMPLETE-TITLE": "Αυτόματη Συμπλήρωση Δεδομένων",
|
||||||
"FIELD-AUTOCOMPLETE-PLACEHOLDER": "Τοποθέτηση placeholder",
|
"FIELD-AUTOCOMPLETE-PLACEHOLDER": "Τοποθέτηση placeholder",
|
||||||
|
"FIELD-AUTOCOMPLETE-SOURCE-TITLE": "Sources",
|
||||||
|
"FIELD-AUTOCOMPLETE-ADD_SOURCE": "Add Source",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE": "Source Type",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE-UNCACHED": "Uncached",
|
||||||
|
"FIELD-AUTOCOMPLETE-TYPE-CACHED": "Cached",
|
||||||
"FIELD-AUTOCOMPLETE-LABEL": "Ετικέτα",
|
"FIELD-AUTOCOMPLETE-LABEL": "Ετικέτα",
|
||||||
"FIELD-AUTOCOMPLETE-VALUE": "Τιμή",
|
"FIELD-AUTOCOMPLETE-VALUE": "Τιμή",
|
||||||
"FIELD-AUTOCOMPLETE-SOURCE": "Πηγή",
|
"FIELD-AUTOCOMPLETE-SOURCE": "Πηγή",
|
||||||
|
|
Loading…
Reference in New Issue