Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Privacy changes #11

Merged
merged 11 commits into from
Apr 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/create_image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Build custom redash image

on:
push:
tags:
- '*'

jobs:
deploy:
permissions:
contents: 'read'
id-token: 'write'
environment:
name: Prod
url: "app.{{ vars.BASE_DOMAIN }}"
runs-on: ubuntu-latest
env:
IMAGE_NAME: asia-south1-python.pkg.dev/prod-data-platform/redash/redash

steps:
- uses: actions/checkout@v3
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v1'
with:
workload_identity_provider: 'projects/1027534050611/locations/global/workloadIdentityPools/github-pool/providers/github'
service_account: 'prod-data-eng-deployment@prod-data-platform.iam.gserviceaccount.com'
token_format: 'access_token'

- uses: olegtarasov/get-tag@v2.1
id: tag_name

- # Add support for more platforms with QEMU (optional)
# https://github.com/docker/setup-qemu-action
name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
platforms: linux/amd64,linux/arm64

- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: "${{ vars.IMAGE_NAME }}:${{ steps.tag_name.outputs.tag }}"
cache-from: type=gha
cache-to: type=gha,mode=max
5 changes: 4 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
FROM node:14.17 as frontend-builder
# syntax=docker/dockerfile:1.3
FROM node:19 as frontend-builder

RUN npm install --global --force yarn@1.22.10

Expand All @@ -19,6 +20,8 @@ COPY --chown=redash viz-lib /frontend/viz-lib
ARG code_coverage
ENV BABEL_ENV=${code_coverage:+test}

ENV NODE_OPTIONS=--openssl-legacy-provider

RUN if [ "x$skip_frontend_build" = "x" ] ; then yarn --frozen-lockfile --network-concurrency 1; fi

COPY --chown=redash client /frontend/client
Expand Down
65 changes: 39 additions & 26 deletions client/app/pages/queries/QuerySource.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { extend, find, includes, isEmpty, map } from "lodash";
import React, { useCallback, useEffect, useRef, useState } from "react";
import {extend, find, includes, isEmpty, map} from "lodash";
import React, {useCallback, useEffect, useRef, useState} from "react";
import PropTypes from "prop-types";
import cx from "classnames";
import { useDebouncedCallback } from "use-debounce";
import {useDebouncedCallback} from "use-debounce";
import useMedia from "use-media";
import Button from "antd/lib/button";
import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession";
Expand All @@ -11,7 +11,7 @@ import Parameters from "@/components/Parameters";
import EditInPlace from "@/components/EditInPlace";
import DynamicComponent from "@/components/DynamicComponent";
import recordEvent from "@/services/recordEvent";
import { ExecutionStatus } from "@/services/query-result";
import {ExecutionStatus} from "@/services/query-result";
import routes from "@/services/routes";
import notification from "@/services/notification";
import * as queryFormat from "@/lib/queryFormat";
Expand All @@ -22,9 +22,10 @@ import QueryVisualizationTabs from "./components/QueryVisualizationTabs";
import QueryExecutionStatus from "./components/QueryExecutionStatus";
import QuerySourceAlerts from "./components/QuerySourceAlerts";
import wrapQueryPage from "./components/wrapQueryPage";
import QueryExecutionMetadataAdditionalInfo from "./components/QueryExecutionMetadataAdditionalInfo";
import QueryExecutionMetadata from "./components/QueryExecutionMetadata";

import { getEditorComponents } from "@/components/queries/editor-components";
import {getEditorComponents} from "@/components/queries/editor-components";
import useQuery from "./hooks/useQuery";
import useVisualizationTabHandler from "./hooks/useVisualizationTabHandler";
import useAutocompleteFlags from "./hooks/useAutocompleteFlags";
Expand Down Expand Up @@ -52,14 +53,14 @@ function chooseDataSourceId(dataSourceIds, availableDataSources) {
}

function QuerySource(props) {
const { query, setQuery, isDirty, saveQuery } = useQuery(props.query);
const { dataSourcesLoaded, dataSources, dataSource } = useQueryDataSources(query);
const {query, setQuery, isDirty, saveQuery} = useQuery(props.query);
const {dataSourcesLoaded, dataSources, dataSource} = useQueryDataSources(query);
const [schema, setSchema] = useState([]);
const queryFlags = useQueryFlags(query, dataSource);
const [parameters, areParametersDirty, updateParametersDirtyFlag] = useQueryParameters(query);
const [selectedVisualization, setSelectedVisualization] = useVisualizationTabHandler(query.visualizations);
const { QueryEditor, SchemaBrowser } = getEditorComponents(dataSource && dataSource.type);
const isMobile = !useMedia({ minWidth: 768 });
const {QueryEditor, SchemaBrowser} = getEditorComponents(dataSource && dataSource.type);
const isMobile = !useMedia({minWidth: 768});

useUnsavedChangesAlert(isDirty);

Expand All @@ -82,7 +83,7 @@ function QuerySource(props) {
const [autoLimitAvailable, autoLimitChecked, setAutoLimit] = useAutoLimitFlags(dataSource, query, setQuery);

const [handleQueryEditorChange] = useDebouncedCallback(queryText => {
setQuery(extend(query.clone(), { query: queryText }));
setQuery(extend(query.clone(), {query: queryText}));
}, 100);

useEffect(() => {
Expand All @@ -101,7 +102,7 @@ function QuerySource(props) {
const formatQuery = () => {
try {
const formattedQueryText = queryFormat.formatQuery(query.query, querySyntax);
setQuery(extend(query.clone(), { query: formattedQueryText }));
setQuery(extend(query.clone(), {query: formattedQueryText}));
} catch (err) {
notification.error(String(err));
}
Expand All @@ -117,14 +118,14 @@ function QuerySource(props) {
}
}
if (query.data_source_id !== dataSourceId) {
recordEvent("update_data_source", "query", query.id, { dataSourceId });
recordEvent("update_data_source", "query", query.id, {dataSourceId});
const updates = {
data_source_id: dataSourceId,
latest_query_data_id: null,
latest_query_data: null,
};
setQuery(extend(query.clone(), updates));
updateQuery(updates, { successMessage: null }); // show message only on error
updateQuery(updates, {successMessage: null}); // show message only on error
}
},
[query, setQuery, updateQuery]
Expand Down Expand Up @@ -193,15 +194,15 @@ function QuerySource(props) {
const deleteVisualization = useDeleteVisualization(query, setQuery);

return (
<div className={cx("query-page-wrapper", { "query-fixed-layout": !isMobile })}>
<QuerySourceAlerts query={query} dataSourcesAvailable={!dataSourcesLoaded || dataSources.length > 0} />
<div className={cx("query-page-wrapper", {"query-fixed-layout": !isMobile})}>
<QuerySourceAlerts query={query} dataSourcesAvailable={!dataSourcesLoaded || dataSources.length > 0}/>
<div className="container w-100 p-b-10">
<QueryPageHeader
query={query}
dataSource={dataSource}
sourceMode
selectedVisualization={selectedVisualization}
headerExtra={<DynamicComponent name="QuerySource.HeaderExtra" query={query} />}
headerExtra={<DynamicComponent name="QuerySource.HeaderExtra" query={query}/>}
onChange={setQuery}
/>
</div>
Expand All @@ -225,7 +226,7 @@ function QuerySource(props) {
dataSource={dataSource}
options={query.options.schemaOptions}
onOptionsUpdate={schemaOptions =>
setQuery(extend(query.clone(), { options: { ...query.options, schemaOptions } }))
setQuery(extend(query.clone(), {options: {...query.options, schemaOptions}}))
}
onSchemaUpdate={setSchema}
onItemSelect={handleSchemaItemSelect}
Expand All @@ -246,15 +247,15 @@ function QuerySource(props) {
</div>
)}

{!query.isNew() && <QueryMetadata layout="table" query={query} onEditSchedule={editSchedule} />}
{!query.isNew() && <QueryMetadata layout="table" query={query} onEditSchedule={editSchedule}/>}
</nav>
</Resizable>

<div className="content">
<div className="flex-fill p-relative">
<div
className="p-absolute d-flex flex-column p-l-15 p-r-15"
style={{ left: 0, top: 0, right: 0, bottom: 0, overflow: "auto" }}>
style={{left: 0, top: 0, right: 0, bottom: 0, overflow: "auto"}}>
<Resizable direction="vertical" sizeAttribute="flex-basis">
<div className="row editor">
<section className="query-editor-wrapper" data-test="QueryEditor">
Expand Down Expand Up @@ -317,19 +318,19 @@ function QuerySource(props) {
dataSourceSelectorProps={
dataSource
? {
disabled: !queryFlags.canEdit,
value: dataSource.id,
onChange: handleDataSourceChange,
options: map(dataSources, ds => ({ value: ds.id, label: ds.name })),
}
disabled: !queryFlags.canEdit,
value: dataSource.id,
onChange: handleDataSourceChange,
options: map(dataSources, ds => ({value: ds.id, label: ds.name})),
}
: false
}
/>
</section>
</div>
</Resizable>

{!queryFlags.isNew && <QueryMetadata layout="horizontal" query={query} onEditSchedule={editSchedule} />}
{!queryFlags.isNew && <QueryMetadata layout="horizontal" query={query} onEditSchedule={editSchedule}/>}

<section className="query-results-wrapper">
{query.hasParameters() && (
Expand Down Expand Up @@ -393,7 +394,7 @@ function QuerySource(props) {
disabled={!queryFlags.canExecute || areParametersDirty}
loading={isQueryExecuting}
onClick={doExecuteQuery}>
{!isQueryExecuting && <i className="zmdi zmdi-refresh m-r-5" aria-hidden="true" />}
{!isQueryExecuting && <i className="zmdi zmdi-refresh m-r-5" aria-hidden="true"/>}
Refresh Now
</Button>
}
Expand All @@ -403,6 +404,18 @@ function QuerySource(props) {
</section>
</div>
</div>
{queryResult && !queryResult.getError() && (
<div className="bottom-controller-container">
<QueryExecutionMetadataAdditionalInfo
query={query}
queryResult={queryResult}
selectedVisualization={selectedVisualization}
isQueryExecuting={isQueryExecuting}
showEditVisualizationButton={!queryFlags.isNew && queryFlags.canEdit}
onEditVisualization={editVisualization}
/>
</div>
)}
{queryResult && !queryResult.getError() && (
<div className="bottom-controller-container">
<QueryExecutionMetadata
Expand Down
15 changes: 8 additions & 7 deletions client/app/pages/queries/components/QueryExecutionMetadata.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,18 +70,19 @@ export default function QueryExecutionMetadata({
{queryResultData.metadata.data_scanned && (
<span className="m-l-5">
Data Scanned:
<strong>{prettySize(queryResultData.metadata.data_scanned)}</strong>
</span>
)}
{queryResultData.metadata.slots_used && (
<span className="m-l-5">
Slots used:
<strong>{formatNumber(queryResultData.metadata.slots_used)}</strong>
<strong> {prettySize(queryResultData.metadata.data_scanned)} </strong>
</span>
)}

</span>
<div>
<span className="m-r-10">
{queryResultData.metadata.slots_used && (
<span className="metadata-info m-l-5">
Slots used:
<strong> {formatNumber(queryResultData.metadata.slots_used)} </strong>
</span>
)}
<span className="hidden-xs">Refreshed </span>
<strong>
<TimeAgo date={queryResultData.retrievedAt} placeholder="-"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.metadata-info {
color: indianred;
}

.query-execution-metadata {
padding: 10px 15px;
background: #fff;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";
import PropTypes from "prop-types";
import useQueryResultData from "@/lib/useQueryResultData";

import "./QueryExecutionMetadataAdditionalInfo.less";

export default function QueryExecutionMetadataAdditionalInfo({
query,
queryResult,
isQueryExecuting,
selectedVisualization,
showEditVisualizationButton,
onEditVisualization,
extraActions,
}) {
const queryResultData = useQueryResultData(queryResult);
return (
<div className="query-execution-metadata">
{extraActions}
<span className="m-l-5 m-r-10">
{queryResultData.metadata.policy_tag_columns && (
<span className="policy_text m-l-5">
<strong>WARNING: </strong>
{queryResultData.metadata.policy_tag_columns}
</span>
)}
</span>
</div>
);
}

QueryExecutionMetadataAdditionalInfo.propTypes = {
query: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
queryResult: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
isQueryExecuting: PropTypes.bool,
selectedVisualization: PropTypes.number,
showEditVisualizationButton: PropTypes.bool,
onEditVisualization: PropTypes.func,
extraActions: PropTypes.node,
};

QueryExecutionMetadataAdditionalInfo.defaultProps = {
isQueryExecuting: false,
selectedVisualization: null,
showEditVisualizationButton: false,
onEditVisualization: () => {
},
extraActions: null,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.policy_text{
color: #0c7cd5;
}

.query-execution-metadata {
padding: 10px 15px;
background: #0a6ebd;
display: flex;
align-items: center;

button,
div,
span {
position: relative;
}

div:last-child {
flex-grow: 1;
text-align: right;
}

&:before {
content: "";
height: 50px;
position: fixed;
bottom: 0;
width: 100%;
pointer-events: none;
left: 0;
}
}
Loading