Skip to content

Commit

Permalink
Merge pull request #154 from dekart-xyz/data-updated-at
Browse files Browse the repository at this point in the history
Report data updated label
  • Loading branch information
delfrrr committed Dec 12, 2023
2 parents dc00dbb + 15ceff5 commit 7cb0fd0
Show file tree
Hide file tree
Showing 13 changed files with 123 additions and 65 deletions.
2 changes: 1 addition & 1 deletion src/client/HomePage.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ function ArchiveButton ({ report }) {
const columns = [
{
dataIndex: 'title',
render: (t, report) => <a href={`/reports/${report.id}/source`}>{report.title}</a>,
render: (t, report) => <a href={`/reports/${report.id}`}>{report.title}</a>,
className: styles.titleColumn
},
{
Expand Down
25 changes: 10 additions & 15 deletions src/client/Query.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,16 @@ import Button from 'antd/es/button'
import styles from './Query.module.css'
import { useDispatch, useSelector } from 'react-redux'
import 'ace-builds/src-noconflict/mode-sql'
// import 'ace-builds/src-noconflict/theme-textmate'
import 'ace-builds/src-noconflict/theme-sqlserver'
import 'ace-builds/src-noconflict/ext-language_tools'
import 'ace-builds/webpack-resolver'
import { Query as QueryType } from '../proto/dekart_pb'
import { SendOutlined, CheckCircleTwoTone, ExclamationCircleTwoTone, ClockCircleTwoTone } from '@ant-design/icons'
import { Duration } from 'luxon'
import prettyBites from 'pretty-bytes'
import DataDocumentationLink from './DataDocumentationLink'
import { cancelQuery, queryChanged, runQuery } from './actions/query'
import { showDataTable } from './actions/showDataTable'
import Tooltip from 'antd/es/tooltip'

function CancelButton ({ query }) {
const dispatch = useDispatch()
Expand Down Expand Up @@ -76,14 +75,6 @@ function StatusActions ({ query }) {
)
}

function Processed ({ query }) {
if (query.bytesProcessed) {
return (<span className={styles.processed}>({prettyBites(query.bytesProcessed)} processed)</span>)
} else {
return (<span className={styles.processed}>(cached)</span>)
}
}

function QueryEditor ({ queryId, queryText, onChange, canWrite }) {
return (
<div className={styles.editor}>
Expand Down Expand Up @@ -116,7 +107,7 @@ function QueryEditor ({ queryId, queryText, onChange, canWrite }) {
}

function QueryStatus ({ children, query }) {
let message, errorMessage, action, style
let message, errorMessage, action, style, tooltip
let icon = null
if (query.jobError) {
message = 'Error'
Expand All @@ -126,6 +117,7 @@ function QueryStatus ({ children, query }) {
}
switch (query.jobStatus) {
case QueryType.JobStatus.JOB_STATUS_PENDING:
icon = <ClockCircleTwoTone className={styles.icon} twoToneColor='#B8B8B8' />
message = 'Pending'
style = styles.info
action = <StatusActions query={query} />
Expand All @@ -145,7 +137,7 @@ function QueryStatus ({ children, query }) {
break
}
icon = <CheckCircleTwoTone className={styles.icon} twoToneColor='#52c41a' />
message = <span>Ready <Processed query={query} /></span>
message = <span>Ready</span>
style = styles.success
action = <ShowDataTable query={query} />
break
Expand All @@ -157,7 +149,7 @@ function QueryStatus ({ children, query }) {
break
case QueryType.JobStatus.JOB_STATUS_DONE:
icon = <CheckCircleTwoTone className={styles.icon} twoToneColor='#52c41a' />
message = <span>Ready <Processed query={query} /></span>
message = <span>Ready</span>
style = styles.success
action = <ShowDataTable query={query} />
break
Expand All @@ -167,8 +159,11 @@ function QueryStatus ({ children, query }) {
<div className={[styles.queryStatus, style].join(' ')}>
<div className={styles.status}>
<div className={styles.statusHead}>
{icon}
<div id='dekart-query-status-message' className={styles.message}>{message}</div>
<Tooltip title={tooltip} className={styles.tooltip}>
{icon}
<div id='dekart-query-status-message' className={styles.message}>{message}</div>
</Tooltip>
<div className={styles.spacer} />
{action ? <div className={styles.action}>{action}</div> : null}
</div>
{errorMessage ? <div className={styles.errorMessage}>{errorMessage}</div> : null}
Expand Down
17 changes: 12 additions & 5 deletions src/client/Query.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,20 @@
margin-right: 10px;
}

.spacer {
flex: 1;
}

.tooltip {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 10px;
}

.message {
font-size: 1.1em;
flex: 1;
white-space: nowrap;
}

.queryStatus {
Expand Down Expand Up @@ -81,10 +92,6 @@
margin-right: 10px;
}

.processed {
font-size: 0.8em
}

.dataDoc {
position: absolute;
bottom: 10px;
Expand Down
12 changes: 12 additions & 0 deletions src/client/ReportHeaderButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,24 @@ function RefreshButton () {
switch (q.jobStatus) {
case Query.JobStatus.JOB_STATUS_PENDING:
case Query.JobStatus.JOB_STATUS_RUNNING:
case Query.JobStatus.JOB_STATUS_READING_RESULTS:
return loadingNumber + 1
default:
return loadingNumber
}
}, 0)
const completedQueries = queries.reduce((n, q) => {
switch (q.jobStatus) {
case Query.JobStatus.JOB_STATUS_DONE:
return n + 1
default:
return n
}
}, 0)
const dispatch = useDispatch()
if (completedQueries === 0 && loadingNumber === 0) {
return null
}
if (!canWrite && !discoverable) {
return null
}
Expand Down
82 changes: 60 additions & 22 deletions src/client/ReportPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import getDatasetName from './lib/getDatasetName'
import { createDataset, openDatasetSettingsModal, setActiveDataset } from './actions/dataset'
import { closeReport, openReport, reportTitleChange } from './actions/report'
import { setError } from './actions/message'
import Tooltip from 'antd/es/tooltip'
import prettyBites from 'pretty-bytes'

function TabIcon ({ query }) {
let iconColor = 'transparent'
Expand All @@ -28,6 +30,8 @@ function TabIcon ({ query }) {
}
switch (query.jobStatus) {
case QueryType.JobStatus.JOB_STATUS_RUNNING:
case QueryType.JobStatus.JOB_STATUS_PENDING:
case QueryType.JobStatus.JOB_STATUS_READING_RESULTS:
iconColor = '#B8B8B8'
break
case QueryType.JobStatus.JOB_STATUS_DONE:
Expand Down Expand Up @@ -63,18 +67,42 @@ function getOnTabEditHandler (dispatch, reportId) {
}
}

function getQueryTooltip (query) {
if (!query) {
return null
}
if (query.jobStatus !== QueryType.JobStatus.JOB_STATUS_DONE) {
return null
}
const updatedAt = new Date(query.updatedAt * 1000)

const processed = query.bytesProcessed ? `Processed ${prettyBites(query.bytesProcessed)}` : 'cached'
return (
<span className={styles.queryTooltip}>
<span title={updatedAt.toISOString()}>{updatedAt.toLocaleString()}</span>
<span>{processed}</span>
{
query.resultSize ? <span>Result {prettyBites(query.resultSize)}</span> : null
}
</span>
)
}

function getTabPane (dataset, queries, files, status) {
let changed = false
const title = getDatasetName(dataset, queries, files)
let tabIcon = null
let tooltip = null
if (dataset.queryId) {
const query = queries.find(q => q.id === dataset.queryId)
tooltip = getQueryTooltip(query)
tabIcon = <TabIcon query={query} />
changed = status.changed
}
const tabTitle = `${title}${changed ? '*' : ''}`
return (
<Tabs.TabPane
tab={<>{tabIcon}{`${title}${changed ? '*' : ''}`}</>}
tab={<Tooltip placement='bottom' title={tooltip}>{tabIcon}{tabTitle}</Tooltip>}
key={dataset.id}
closable
closeIcon={<span title='Dataset setting'><MoreOutlined /></span>}
Expand Down Expand Up @@ -217,29 +245,24 @@ function Kepler () {
const dispatch = useDispatch()
if (!env.loaded) {
return (
<div className={styles.keplerFlex}>
<div className={styles.keplerBlock} />
</div>
<div className={styles.keplerBlock} />
)
}
return (
<div className={styles.keplerFlex}>
<div className={styles.keplerBlock}>
<AutoSizer>
{({ height, width }) => (
<CatchKeplerError onError={(err) => dispatch(setError(err))}>
<KeplerGl
id='kepler'
mapboxApiAccessToken={env.variables.MAPBOX_TOKEN}
width={width}
height={height}
/>
</CatchKeplerError>
)}
</AutoSizer>
</div>
<div className={styles.keplerBlock}>
<AutoSizer>
{({ height, width }) => (
<CatchKeplerError onError={(err) => dispatch(setError(err))}>
<KeplerGl
id='kepler'
mapboxApiAccessToken={env.variables.MAPBOX_TOKEN}
width={width}
height={height}
/>
</CatchKeplerError>
)}
</AutoSizer>
</div>

)
}

Expand All @@ -250,6 +273,15 @@ export default function ReportPage ({ edit }) {
const report = useSelector(state => state.report)
const envLoaded = useSelector(state => state.env.loaded)
const { mapConfig, title } = report || {}
const files = useSelector(state => state.files || [])
const queries = useSelector(state => state.queries || [])
const updatedAt = [].concat(files, queries).reduce((updatedAt, item) => {
if (item.updatedAt > updatedAt) {
return item.updatedAt
}
return updatedAt
}, 0)
const updatedAtDate = new Date(updatedAt * 1000)
const reportStatus = useSelector(state => state.reportStatus)
const queryChanged = useSelector(state => Object.values(state.queryStatus).reduce((queryChanged, queryStatus) => {
return queryStatus.changed || queryChanged
Expand Down Expand Up @@ -286,8 +318,14 @@ export default function ReportPage ({ edit }) {
/>)}
/>
<div className={styles.body}>
<Kepler />
{report.authorEmail !== 'UNKNOWN_EMAIL' ? <div className={styles.author}>Author: {report.authorEmail}</div> : null}
<div className={styles.keplerFlex}>
<Kepler />
<div className={styles.meta}>
{updatedAt ? <span className={styles.lastUpdated} title={`${updatedAtDate.toISOString()}`}>{updatedAtDate.toLocaleString()}</span> : null}
{updatedAt && report.authorEmail !== 'UNKNOWN_EMAIL' ? <span className={styles.dot}> | </span> : null}
{report.authorEmail !== 'UNKNOWN_EMAIL' ? <span className={styles.author} title='Report author'>{report.authorEmail}</span> : null}
</div>
</div>
{edit ? <DatasetSection reportId={id} /> : null}
</div>
</div>
Expand Down
15 changes: 9 additions & 6 deletions src/client/ReportPage.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,13 @@
flex: 1;
}

.author {
.meta {
position: absolute;
height: 30px;
height: 20px;
bottom: 0px;
left: 20px;
color: #6C7483;
font-size: 0.8em;
display: flex;
flex-direction: column;
justify-content: center;
font-size: 0.7em;
}

.tabs {
Expand Down Expand Up @@ -127,6 +124,12 @@
right: 0;
}

.queryTooltip span{
display: block;
font-size: 0.8em;
white-space: nowrap;
}

.keplerFlex {
flex: 1;
position: relative;
Expand Down
2 changes: 1 addition & 1 deletion src/proto/dekart.pb.go

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

2 changes: 1 addition & 1 deletion src/server/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"google.golang.org/grpc"
)

// ResponseWriter implementation which allows to oweride status code
// ResponseWriter implementation which allows to override status code
type ResponseWriter struct {
w http.ResponseWriter
statusCode int
Expand Down
10 changes: 5 additions & 5 deletions src/server/dekart/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import (

func (s Server) getFileReports(ctx context.Context, fileId string, claims *user.Claims) ([]string, error) {
fileRows, err := s.db.QueryContext(ctx,
`select
`select
reports.id
from files
left join datasets on files.id = datasets.file_id
Expand Down Expand Up @@ -50,7 +50,7 @@ func (s Server) setUploadError(reportIDs []string, fileSourceID string, err erro
defer cancel()
_, err = s.db.ExecContext(
ctx,
`update files set upload_error=$1 where file_source_id=$2`,
`update files set upload_error=$1, updated_at=now() where file_source_id=$2`,
err.Error(),
fileSourceID,
)
Expand Down Expand Up @@ -92,7 +92,7 @@ func (s Server) moveFileToStorage(reqCtx context.Context, fileSourceID string, f
}
log.Debug().Msgf("file %s.csv moved to storage", fileSourceID)
_, err = s.db.ExecContext(ctx,
`update files set file_status=3 where file_source_id=$1`,
`update files set file_status=3, updated_at=now() where file_source_id=$1`,
fileSourceID,
)
if err != nil {
Expand Down Expand Up @@ -158,7 +158,7 @@ func (s Server) UploadFile(w http.ResponseWriter, r *http.Request) {
fileSourceID := newUUID()

_, err = s.db.ExecContext(ctx,
`update files set name=$1, size=$2, mime_type=$3, file_status=2, file_source_id=$4 where id=$5`,
`update files set name=$1, size=$2, mime_type=$3, file_status=2, file_source_id=$4, updated_at=now() where id=$5`,
handler.Filename,
handler.Size,
mimeType,
Expand Down Expand Up @@ -207,7 +207,7 @@ func (s Server) CreateFile(ctx context.Context, req *proto.CreateFileRequest) (*
}

result, err := s.db.ExecContext(ctx,
`update datasets set file_id=$1 where id=$2 and file_id is null`,
`update datasets set file_id=$1, updated_at=now() where id=$2 and file_id is null`,
id,
req.DatasetId,
)
Expand Down
Loading

0 comments on commit 7cb0fd0

Please sign in to comment.