Tabulator.js 5.2 datetime formatter with luxon.js, how to configure inputFormat for unix timestamps - tabulator

I have a dataset with unix timestamp and want to display a readable date. Which inputFormat do I have to configure (using tabulator 5.2)?
I am switching from tabulator 4.9 to 5.2, which also changes the library used for the formatter:"datetime" from moment.js to luxon.js. With moment.js the formatterParams below worked.
formatterParams:{
inputFormat:"unix",
outputFormat:"DD/MM/YY HH:mm",
invalidPlaceholder:"(invalid date)"
}
With the luxon.js this doesn't work and I don't know which inputFormat to configure.
EDIT:
Relevant parts of the table
var event_table = new Tabulator("#events-table", {
height: "750",
layout: "fitDataTable",
movableRows: true,
ajaxURL: [],
columns: [
{ rowHandle: true, formatter: "handle", headerSort: false, frozen: true, width: 30, minWidth: 30 },
{
title: "Time", field: "timestamp", headerFilter: "input", formatter: "datetime", formatterParams: {
inputFormat: "unix",
outputFormat: "DD/MM/YY HH:mm",
invalidPlaceholder: "(invalid date)"
}
},
{ title: "Typ", field: "type", headerFilter: "list", headerFilterParams: { values: true } }
]
});
data:
[
{
"timestamp": 1655845814046,
"type": "weight"
},
{
"timestamp": 1655845931252,
"type": "weight"
},
{
"timestamp": 1655877784130,
"type": "amount"
},
{
"timestamp": 1655877828127,
"type": "weight"
}
]

Please note that "unix" is not "officially" supported by Tabulator 4.9, I don't see it mentioned in the DateTime built-in formatters.
It works because tabulator uses var newDatetime = moment(value, inputFormat); to parse cell value. So tabulator uses moment(String, String) that is is very forgiving, in your case it parse correctly the unix timestamp since the "unix" string used as format token contains the x that represents the token for Unix ms timestamp.
Luxon has no counterpart for moment x, you should use DateTime.fromMillis to parse Unix timestamps. There seems to be no way to use DateTime.fromMillis using DateTime formatter of version 5.2 of tabulator (see its code).
You can instead use a custom formatter:
As well as the built-in formatters you can define a formatter using a custom formatter function.
The formatter function accepts two arguments, the CellComponent for the cell being formatted and the formatterParams option from the column definition.
The function must return the contents of the cell, either the text value of the cell, valid HTML or a DOM node.
Example:
var tabledata = [{
"timestamp": 1655845814046,
"type": "weight"
},
{
"timestamp": 1655845931252,
"type": "weight"
},
{
"timestamp": 1655877784130,
"type": "amount"
},
{
"timestamp": 1655877828127,
"type": "weight"
}
];
var event_table = new Tabulator("#events-table", {
data: tabledata,
height: "750",
layout: "fitDataTable",
//movableRows: true,
//ajaxURL: [],
columns: [{
rowHandle: true,
formatter: "handle",
headerSort: false,
frozen: true,
width: 30,
minWidth: 30
},
{
title: "Time",
field: "timestamp",
headerFilter: "input",
formatter: function(cell, formatterParams, onRendered) {
try {
let dt = luxon.DateTime.fromMillis(cell.getValue());
return dt.toFormat(formatterParams.outputFormat);
} catch (error) {
return formatterParams.invalidPlaceholder;
}
},
formatterParams: {
outputFormat: "dd/MM/yy HH:mm",
invalidPlaceholder: "(invalid date)"
}
},
{
title: "Typ",
field: "type",
headerFilter: "list",
headerFilterParams: {
values: true
}
}
]
});
<link href="https://unpkg.com/tabulator-tables#5.2.7/dist/css/tabulator.min.css" rel="stylesheet">
<script type="text/javascript" src="https://unpkg.com/tabulator-tables#5.2.7/dist/js/tabulator.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/luxon#2.4.0/build/global/luxon.min.js"></script>
<div id="events-table"></div>

Related

elasticsearch doesn't find results when searching the exact term

I am using the elasticsearch module in my nodejs app to query my index using fuzzy completion. The text I'm trying to search is Rome–Fiumicino Leonardo da Vinci International Airport. when searching this term I get no results, but if I cut the term to 50 characters it does find it and return results.
const result = await elasticsearch.search({
index: 'myIndex',
body: {
suggest: {
fuzzinessZero: {
text,
completion: {
field: 'name_suggest',
fuzzy: {
fuzziness: 0,
},
contexts,
},
},
fuzzinessOne: {
text,
completion: {
field: 'name_suggest',
fuzzy: {
fuzziness: 1,
},
contexts,
},
},
fuzzinessTwo: {
text,
completion: {
field: 'name_suggest',
fuzzy: {
fuzziness: 2,
},
contexts,
},
},
},
}
})
This is the result I get in fuzzinessOne
As you can see, the result in the text field is cut to 50 characters (maybe that's the issue). And inside the _source I get back all the inputs which is used for the search, and one of them is the full exact term which I tried to search, as well with all the other available combinations available.
It is worth mentioning that I'm using AWS openSearch.
And this is the settings which I use to create the index:
settings: {
analysis: {
filter: {
autocomplete_filter: {
type: 'edge_ngram',
min_gram: 2,
max_gram: 20,
},
shingle_filter: {
type: 'shingle',
max_shingle_size: 3,
},
},
analyzer: {
autocomplete: {
type: 'custom',
tokenizer: 'standard',
filter: ['lowercase', 'shingle_filter', 'asciifolding'],
},
},
},
}
You are facing this issue because of default value of max_input_length parameter is set to 50.
Below is description given for this parameter in documentation:
Limits the length of a single input, defaults to 50 UTF-16 code
points. This limit is only used at index time to reduce the total
number of characters per input string in order to prevent massive
inputs from bloating the underlying datastructure. Most use cases
won’t be influenced by the default value since prefix completions
seldom grow beyond prefixes longer than a handful of characters.
You can use this default behaviour or you can updated your index mapping with increase value of max_input_length parameter and reindex your data.
{
"mappings": {
"dynamic": "false",
"properties": {
"namesuggest": {
"type": "completion",
"analyzer": "keyword_lowercase_analyzer",
"preserve_separators": true,
"preserve_position_increments": true,
"max_input_length": 100,
"contexts": [
{
"name": "searchable",
"type": "CATEGORY"
}
]
}
}
},
"settings": {
"index": {
"mapping": {
"ignore_malformed": "true"
},
"refresh_interval": "5s",
"analysis": {
"analyzer": {
"keyword_lowercase_analyzer": {
"filter": [
"lowercase"
],
"type": "custom",
"tokenizer": "keyword"
}
}
},
"number_of_replicas": "0",
"number_of_shards": "1"
}
}
}

Query Doesn't Match Numbers In Text

Match queries can find strings that contain numbers, in this case, I am trying to search matching phone numbers. Mappings and analyzers are provided below. For example, I have an index as follows
{
"userId": 126817,
"name": "Test User",
"phoneNumber": "5551112233",
}
When I use match query doesn't match anything
{"match" : {"phoneNumber": {"query": "555"}}}
When I use prefix value it does match
{"prefix" : {"phoneNumber": {"value ": "555"}}}
Analyze Results
{
"tokens": [
{
"token": "5551112233",
"start_offset": 0,
"end_offset": 10,
"type": "<NUM>",
"position": 0
}
]
}
Mapping
{
index: "user-clinics",
type: "user-clinic",
body: {properties: {id: {type: "long"}} }
}
Analyzers
const TurkishAnalyzer = {
analysis: {
filter: {
my_ascii_folding: {
type: "asciifolding",
preserve_original: true
}
},
analyzer: {
turkish_analyzer: {
tokenizer: "standard",
filter: ["lowercase", "my_ascii_folding"]
}
}
}
};
const AutoCompleteAnalyzer = {
analysis: {
filter: {
autocomplete_filter: {
type: "edge_ngram",
min_gram: 1,
max_gram: 20
}
},
analyzer: {
autocomplete_search: {
type: "custom",
tokenizer: "standard",
filter: ["lowercase"]
},
autocomplete_index: {
type: "custom",
tokenizer: "standard",
filter: ["lowercase", "autocomplete_filter"]
}
}
}
};
It's because edge_ngram tokenizes only from the beginning of the token, hence all prefixes will be indexed, i.e. a, as, asd, asd1, asd12, asd123
You need to change your autocomplete_filter to ngram if you also want to be able to match inside tokens, i.e. d12 or 123.
Beware, though, that this might generate a lot more tokens

How to show data in React Table with structure {_id:" xx",timestamp:"xx" ,message:"{"temperature:22","humi":45}" }?

React-Table
I have made an axios.get request to the back-end which in turn gives a large data-set from mongodb. The
structure of data returned is :
[
1: {_id: "5dd3be2ecf55e1ec388f502b", timestamp: 1574157870567, message: "{"temperature":58,"humidity":59,"pressure":"1 bar"}"}
2: {_id: "5dd3be2ecf55e1ec388f502a", timestamp: 1574157870067, message: "{"temperature":78,"humidity":79,"pressure":"1 bar"}"}
...
]
I want to show it to react-table.The id and timestamp is being displayed but the temperature and other variable are not being displayed.The message is string.How can I parse such amount of data at back-end to convert message into object?
Back-end code
router.get('/viewData',async(req,res) =>{
collection.find({},{_id:0,timestamp:0}).sort({timestamp:-1}).limit(400).toArray(function (err, resultantData) {
if (err)
throw err;
//var storedDataArray ;
//var gotData=[];
//var index =0;
//storedDataArray=resultantData;
//console.log(storedDataArray)
// storedDataArray.forEach(element => {
// gotData[index]=JSON.parse(element);
// console.log(gotData[index])
// index++;
// })
// console.log(gotData.length);
res.status(200).json(resultantData);
});
Is there any way to show temperature and other quantities in react table?
React-Table
class deviceData extends Component {
constructor(props) {
super(props)
this.state = {
dataList:[],
data : ' '
};
}
componentDidMount(){
const url="http://localhost:5000/api/data/viewData";
fetch (url,{
method: "GET"
}).then(response=> response.json()).then(result=>{
console.log(result);
this.setState({
dataList : result,
});
});
}
render() {
const columns =[
{
Header:"Message ID",
accessor:"_id",
sortable: true,
filterable: false,
style:{
textAlign: "left"
},
width: 300,
maxWidth: 100,
minWidth: 100,
},
{
Header:"Time Stamp",
accessor:"timestamp",
width: 300,
maxWidth: 100,
minWidth: 100,
},
{
Header:"Temperature",
id:'temperature',
filterable: false,
accessor: 'temperature'
},
{
Header:"Pressure",
id:'pressure',
filterable: false,
accessor: 'pressure'
},
{
Header:"Humidity",
id:'humidity',
filterable: false,
accessor: 'humidity'
},
]
return(
<div className="ReactTable">
<ReactTable
columns={columns}
data={this.state.dataList}
defaultPageSize={10}
className="-striped -highlight"
>
</ReactTable>
<div id={"#"+ this.props.id} ></div>
</div>
);
}
}
[![React-Table][1]][1]
Backend Response
[
{
"_id": "5dd3be2fcf55e1ec388f502c",
"timestamp": 1574157871067,
"message": "{\"temperature\":93,\"humidity\":94,\"pressure\":\"1 bar\"}"
},
{
"_id": "5dd3be2ecf55e1ec388f502b",
"timestamp": 1574157870567,
"message": "{\"temperature\":58,\"humidity\":59,\"pressure\":\"1 bar\"}"
},
{
"_id": "5dd3be2ecf55e1ec388f502a",
"timestamp": 1574157870067,
"message": "{\"temperature\":78,\"humidity\":79,\"pressure\":\"1 bar\"}"
},
{
"_id": "5dd3be2dcf55e1ec388f5029",
"timestamp": 1574157869567,
"message": "{\"temperature\":88,\"humidity\":89,\"pressure\":\"1 bar\"}"
},
{
"_id": "5dd3be2dcf55e1ec388f5028",
"timestamp": 1574157869066,
"message": "{\"temperature\":99,\"humidity\":100,\"pressure\":\"1 bar\"}"
},
{
"_id": "5dd3be2ccf55e1ec388f5027",
"timestamp": 1574157868567,
"message": "{\"temperature\":38,\"humidity\":39,\"pressure\":\"1 bar\"}"
},
{
"_id": "5dd3be2ccf55e1ec388f5026",
"timestamp": 1574157868067,
"message": "{\"temperature\":82,\"humidity\":83,\"pressure\":\"1 bar\"}"
},
{
"_id": "5dd3be2bcf55e1ec388f5025",
"timestamp": 1574157867566,
"message": "{\"temperature\":76,\"humidity\":77,\"pressure\":\"1 bar\"}"
}
]
Convert string back to object by using parse()
ex: var object = JSON.parse(str);
Important thing is to define column with correct accessor. Try this one:
const columns = [
{
Header: "Id",
accessor: "_id"
},
{
Header: "timestamp",
accessor: "timestamp"
},
{
Header: "Temprature",
accessor: "message.temprature"
},
{
Header: "humidity",
accessor: "message.humidity"
},
{
Header: "pressure",
accessor: "message.pressure"
}
];
And Use it in React-table like this:
<ReactTable
data={loans} // Instead of loans, use variable where you store your response
columns={columns}
defaultPageSize={10}
sortable={true}
/>
I think you can try with adding a headers in your fetch method
fetch (url,{
method: "GET",
headers: {
"Accept": "application/json",
"Content-Type": "application/json",
}
})
It will ensure your response is JSON
N.B. Try your url with postman first, setting those headers and see whether result is JSON or not, if it is JSON I believe my code will help you, if it is not a JSON return try to change your back-end code to ensure it return JSON using postman

How to create a dynamic table with vue js

I have a question. How to create a dynamic table with vue js.
I want to render this json file into the table using Vue but it doesn't happen as I want. I want the data in two languages and app_adi but only the latest data is coming. How can I display both?
json file
{
"accounts":{
"user":{
"_id":"5a500vlflg0aslf011ld0a25a5",
"username":"john",
"id":"59d25992988fsaj19fe31d7",
"name":"Test",
"customer":" John Carew",
},
"application":[
{
"app_id":"5af56pi314-y1i96kdnqs871nih35",
"language":"es"
},
{
"app_id":"5af56pi314-blvinpgn4c95ywyt8j",
"language":"en"
}
]
}
}
I want to build this table:
username customer language app_di
john John Carew es 5af56pi314-y1i96kdnqs871nih35
en 5af56pi314-blvinpgn4c95ywyt8j
Preprocess your json in a computed property.
In your example you just need to add the "user" properties to the first "application" item.
new Vue({
el: '#app',
data() {
return {
columns: {
username: 'Name',
customer: 'Customer',
language: 'Language',
app_id: 'App_ID'
},
userData: {
"user": {
"_id": "5a500vlflg0aslf011ld0a25a5",
"username": "john",
"id": "59d25992988fsaj19fe31d7",
"name": "Test",
"customer": " John Carew",
},
"application": [{
"app_id": "5af56pi314-y1i96kdnqs871nih35",
"language": "es"
},
{
"app_id": "5af56pi314-blvinpgn4c95ywyt8j",
"language": "en"
}
]
}
}
},
computed: {
tableData() {
return this.userData.application.map((x, index) => {
return index === 0 ? Object.assign(x, this.userData.user) : x
})
}
}
})
Here is a working example: https://jsfiddle.net/ellisdod/jm3snwxc/2/

No value passed to the slots but Original Value is passed in the bot

I am using Amazon lex with AWS lambda as a validation Codehook. When I was trying to pass a value with a response card dynamically generated, it is showing null value in the AppointmentTime Slot but the original value is showing value in slotDetails.
Here is the request sent through lex:
{
"messageVersion": "1.0",
"invocationSource": "DialogCodeHook",
"userId": "prwna44b91sbr4w7d2pwwva59anaqzqx",
"sessionAttributes": {
"store_id": "26",
"address": "Quark Atrium, A‐45, Phase VIII Extension,Industrial Focal Point,Sahibzada Ajit Singh Nagar, Punjab 160071,India",
"closingTime": "19:00:00",
"city": "Mohali",
"phone": "9718409751",
"bookingDateTime": "2018-05-27T21:25:46+05:30",
"openingTime": "10:00:00",
"state": "PB",
"email": "bhuvnesh.kumar#sourcefuse.com",
"zip_code": "44545"
},
"requestAttributes": null,
"bot": {
"name": "ScheduleRide",
"alias": "$LATEST",
"version": "$LATEST"
},
"outputDialogMode": "Text",
"currentIntent": {
"name": "BookAppointment",
"slots": {
"CustomerAgreement": null,
"DropLocationPrompt": "yes",
"PickupAddress": "Unnamed Road, Industrial Area, Sector 74, Sahibzada Ajit Singh Nagar, Punjab 140308, India",
"RequiredService": null,
"AppointmentTime": null,
"DropAddress": null,
"PhoneNumber": null,
"AppointmentDate": "2018-05-28"
},
"slotDetails": {
"CustomerAgreement": {
"resolutions": [],
"originalValue": null
},
"DropLocationPrompt": {
"resolutions": [
{
"value": "yes"
}
],
"originalValue": "yes"
},
"PickupAddress": {
"resolutions": [],
"originalValue": "Unnamed Road, Industrial Area, Sector 74, Sahibzada Ajit Singh Nagar, Punjab 140308, India"
},
"RequiredService": {
"resolutions": [],
"originalValue": null
},
"AppointmentTime": {
"resolutions": [
{
"value": "00:00"
},
{
"value": "12:00"
}
],
"originalValue": "14:00:00"
},
"DropAddress": {
"resolutions": [],
"originalValue": null
},
"PhoneNumber": {
"resolutions": [],
"originalValue": null
},
"AppointmentDate": {
"resolutions": [],
"originalValue": "28 may"
}
},
"confirmationStatus": "None"
},
"inputTranscript": "14:00:00"
}
Here is the request passed to the lex, see the AppointmentTime in the slots object, it is showing null and in the slotDetails object, it is showing value. Here is the array of buttons which i pass from the response card object:
[ { text: '1:00 PM', value: '13:00:00' },
{ text: '1:30 PM', value: '13:30:00' },
{ text: '2:00 PM', value: '14:00:00' },
{ text: '2:30 PM', value: '14:30:00' },
{ text: '3:00 PM', value: '15:00:00' },
{ text: '3:30 PM', value: '15:30:00' },
{ text: '4:00 PM', value: '16:00:00' },
{ text: '4:30 PM', value: '16:30:00' },
{ text: '5:00 PM', value: '17:00:00' },
{ text: '5:30 PM', value: '17:30:00' },
{ text: '6:00 PM', value: '18:00:00' },
{ text: '6:30 PM', value: '18:30:00' } ]
Here is the function of buildResponseCard:
function buildResponseCard(title, subTitle, options){
let buttons = null;
console.log(options);
let genericAttachments = [];
if (options != null){
buttons = [];
for(let i = 0; i < (options.length); i++){
buttons.push(options[i]);
if(i%3 === 2){
genericAttachments.push({
title,
subTitle,
buttons
});
buttons = [];
}
}
}
return {
version: 1,
contentType: "application/vnd.amazonaws.card.generic",
genericAttachments
};
}
The reason I want AppointmentTime slot value on slot object to be shown on is that whenever the value in the slot is invalid through validation, I will set it to null and will callback it through lambda function and i will not be able to callback the slotDetails object in the response.
Can anyone tell me how can i achieve this?
For the AMAZON.TIME built-in slot:
When a user enters an ambiguous time, Amazon Lex uses the slotDetails attribute of a Lambda event to pass resolutions for the ambiguous times to your Lambda function. ... In this case, the value in the slots map is null, and the slotDetails entity contains the two possible resolutions of the time.
Your input of "14:00:00" is not understood as an unambiguous time, and Lex tries to resolve it to either noon or midnight, which is obviously wrong. This is probably because the Lex Time slot is expecting only hours and minutes (hh:mm) but not seconds (hh:mm:ss).
So if it is possible for you, one solution is to remove the seconds digits from your time values. For example:
[ { text: '1:00 PM', value: '13:00' }, ... ]
However, if you must have the seconds in the time value, then you can simply find the time the user selected from the inputTranscript value and do your validation of it from there.
var userInput = event.inputTranscript;
EDIT:
Another option is to ignore Lex's suggested resolutions and get the slot-details original-value. Like this:
var timeValue = event.currentIntent.slotDetails.AppointmentTime.originalValue;
And then set the AppointmentTime slot yourself. Like this:
event.currentIntent.slots.AppointmentTime = timeValue;

Resources