Skip to content

Commit

Permalink
Merge branch 'fix/notebook-types-stuffs' into feat/better-drag-and-drop
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite committed Sep 11, 2023
2 parents 5b7f7c7 + 2aeab01 commit 7044c90
Show file tree
Hide file tree
Showing 85 changed files with 3,458 additions and 948 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ jobs:
cypress:
name: Cypress E2E tests (${{ strategy.job-index }})
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 60
needs: [chunks, changes]
permissions:
id-token: write # allow issuing OIDC tokens for this workflow run
Expand Down
1 change: 1 addition & 0 deletions .storybook/test-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const LOADER_SELECTORS = [
'.LemonTableLoader',
'[aria-busy="true"]',
'.SessionRecordingPlayer--buffering',
'.Lettermark--unknown',
]

const customSnapshotsDir = `${process.cwd()}/frontend/__snapshots__`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const TheHedgehog: StoryFn<typeof HedgehogBuddy> = () => {
// eslint-disable-next-line no-console
console.log('should close')
}}
isDarkModeOn={false}
/>
</div>
)
Expand Down
12 changes: 9 additions & 3 deletions frontend/src/lib/components/HedgehogBuddy/HedgehogBuddy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -390,17 +390,18 @@ export function HedgehogBuddy({
onClick: _onClick,
onPositionChange,
popoverOverlay,
isDarkModeOn,
}: {
actorRef?: MutableRefObject<HedgehogActor | undefined>
onClose: () => void
onClick?: () => void
onPositionChange?: (actor: HedgehogActor) => void
popoverOverlay?: React.ReactNode
// passed in because toolbar needs to check this differently than the app
isDarkModeOn: boolean
}): JSX.Element {
const actorRef = useRef<HedgehogActor>()

const { isDarkModeOn } = useValues(themeLogic)

if (!actorRef.current) {
actorRef.current = new HedgehogActor()
if (_actorRef) {
Expand Down Expand Up @@ -538,6 +539,11 @@ export function HedgehogBuddy({
export function HedgehogBuddyWithLogic(): JSX.Element {
const { hedgehogModeEnabled } = useValues(hedgehogbuddyLogic)
const { setHedgehogModeEnabled } = useActions(hedgehogbuddyLogic)
const { isDarkModeOn } = useValues(themeLogic)

return hedgehogModeEnabled ? <HedgehogBuddy onClose={() => setHedgehogModeEnabled(false)} /> : <></>
return hedgehogModeEnabled ? (
<HedgehogBuddy onClose={() => setHedgehogModeEnabled(false)} isDarkModeOn={isDarkModeOn} />
) : (
<></>
)
}
3 changes: 3 additions & 0 deletions frontend/src/lib/lemon-ui/Lettermark/Lettermark.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ const meta: Meta<typeof Lettermark> = {
'Lettermarks are used as visual, icon-like representations of actors (project members, organizations, query steps, cohort criteria groups, etc) in the product. Lettermarks should vary between the 8 variants we have shown below. Ideally the same colour is not placed next to each other',
},
},
testOptions: {
waitForLoadersToDisappear: false,
},
},
tags: ['autodocs'],
}
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/lib/lemon-ui/Lettermark/Lettermark.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ export function Lettermark({ name, index, color, rounded = false }: LettermarkPr
className={clsx(
'Lettermark',
colorIndex && `Lettermark--variant-${colorIndex}`,
rounded && `Lettermark--rounded`
rounded && `Lettermark--rounded`,
representation === '?' && 'Lettermark--unknown'
)}
title={String(name)}
>
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/queries/nodes/HogQLQuery/HogQLQueryEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,13 @@ export function HogQLQueryEditor(props: HogQLQueryEditorProps): JSX.Element {
onClick={saveAsView}
type="primary"
center
disabledReason={!isValidView && 'All fields must have an alias'}
disabledReason={
hasErrors
? error ?? 'Query has errors'
: !isValidView
? 'All fields must have an alias'
: ''
}
data-attr="hogql-query-editor-save-as-view"
>
{'Save as View'}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/queries/nodes/SavedInsight/SavedInsight.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function SavedInsight({ query, context, cachedResults }: InsightProps): J

return (
<Query
query={{ kind: NodeKind.InsightVizNode, source: filtersToQueryNode(insight.filters) }}
query={{ ...query, kind: NodeKind.InsightVizNode, source: filtersToQueryNode(insight.filters) }}
context={{ ...context, insightProps }}
/>
)
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1888,12 +1888,41 @@
"SavedInsightNode": {
"additionalProperties": false,
"properties": {
"embedded": {
"description": "Query is embedded inside another bordered component",
"type": "boolean"
},
"full": {
"description": "Show with most visual options enabled. Used in insight scene.",
"type": "boolean"
},
"kind": {
"const": "SavedInsightNode",
"type": "string"
},
"shortId": {
"$ref": "#/definitions/InsightShortId"
},
"showCorrelationTable": {
"type": "boolean"
},
"showFilters": {
"type": "boolean"
},
"showHeader": {
"type": "boolean"
},
"showLastComputation": {
"type": "boolean"
},
"showLastComputationRefresh": {
"type": "boolean"
},
"showResults": {
"type": "boolean"
},
"showTable": {
"type": "boolean"
}
},
"required": ["kind", "shortId"],
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/queries/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,17 +326,19 @@ export interface DataTableNode extends Node {

// Saved insight node

export interface SavedInsightNode extends Node {
export interface SavedInsightNode extends Node, InsightVizNodeViewProps {
kind: NodeKind.SavedInsightNode
shortId: InsightShortId
}

// Insight viz node

export interface InsightVizNode extends Node {
export interface InsightVizNode extends Node, InsightVizNodeViewProps {
kind: NodeKind.InsightVizNode
source: InsightQueryNode
}

interface InsightVizNodeViewProps {
/** Show with most visual options enabled. Used in insight scene. */
full?: boolean
showHeader?: boolean
Expand Down
28 changes: 27 additions & 1 deletion frontend/src/scenes/batch_exports/BatchExportEditForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { LemonBanner } from 'lib/lemon-ui/LemonBanner'
import { LemonCalendarSelectInput } from 'lib/lemon-ui/LemonCalendar/LemonCalendarSelect'
import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
import { LemonSelectMultiple } from 'lib/lemon-ui/LemonSelectMultiple/LemonSelectMultiple'
import { LemonFileInput } from 'lib/lemon-ui/LemonFileInput/LemonFileInput'
import { IconInfo } from 'lib/lemon-ui/icons'
import { BatchExportsEditLogicProps, batchExportsEditLogic } from './batchExportEditLogic'
import { Field } from 'lib/forms/Field'
Expand Down Expand Up @@ -131,9 +132,10 @@ export function BatchExportsEditForm(props: BatchExportsEditLogicProps): JSX.Ele
<Field name="destination" label="Destination">
<LemonSelect
options={[
{ value: 'BigQuery', label: 'BigQuery' },
{ value: 'Postgres', label: 'Postgres' },
{ value: 'S3', label: 'S3' },
{ value: 'Snowflake', label: 'Snowflake' },
{ value: 'Postgres', label: 'Postgres' },
]}
/>
</Field>
Expand Down Expand Up @@ -297,6 +299,30 @@ export function BatchExportsEditForm(props: BatchExportsEditLogicProps): JSX.Ele
/>
</Field>
</>
) : batchExportConfigForm.destination === 'BigQuery' ? (
<>
<Field name="json_config_file" label="Google Cloud JSON key file">
<LemonFileInput accept=".json" multiple={false} />
</Field>

<Field name="table_id" label="Table ID">
<LemonInput placeholder="events" />
</Field>

<Field name="dataset_id" label="Dataset ID">
<LemonInput placeholder="dataset" />
</Field>

<Field name="exclude_events" label="Events to exclude" className="flex-1">
<LemonSelectMultiple
mode="multiple-custom"
options={[]}
placeholder={
'Input one or more events to exclude from the export (optional)'
}
/>
</Field>
</>
) : null}
</div>

Expand Down
12 changes: 11 additions & 1 deletion frontend/src/scenes/batch_exports/BatchExportScene.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,17 @@ export function BatchExportScene(): JSX.Element {
</li>

{Object.keys(batchExportConfig.destination.config)
.filter((x) => !['password', 'aws_secret_access_key'].includes(x))
.filter(
(x) =>
![
'password',
'aws_secret_access_key',
'client_email',
'token_uri',
'private_key',
'private_key_id',
].includes(x)
)
.map((x) => (
<li key={x} className="flex items-center justify-between gap-2">
<span>{identifierToHuman(x)}:</span>
Expand Down
55 changes: 53 additions & 2 deletions frontend/src/scenes/batch_exports/batchExportEditLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { actions, afterMount, connect, kea, key, listeners, path, props, selecto
import {
BatchExportConfiguration,
BatchExportDestination,
BatchExportDestinationBigQuery,
BatchExportDestinationPostgres,
BatchExportDestinationS3,
BatchExportDestinationSnowflake,
Expand All @@ -27,11 +28,13 @@ export type BatchExportConfigurationForm = Omit<
'id' | 'destination' | 'start_at' | 'end_at'
> &
Partial<BatchExportDestinationPostgres['config']> &
Partial<BatchExportDestinationBigQuery['config']> &
Partial<BatchExportDestinationS3['config']> &
Partial<BatchExportDestinationSnowflake['config']> & {
destination: 'S3' | 'Snowflake' | 'Postgres'
destination: 'S3' | 'Snowflake' | 'Postgres' | 'BigQuery'
start_at: Dayjs | null
end_at: Dayjs | null
json_config_file?: File[] | null
}

const formFields = (
Expand Down Expand Up @@ -69,6 +72,23 @@ const formFields = (
compression: '',
exclude_events: '',
}
: destination === 'BigQuery'
? {
json_config_file: isNew
? !config.json_config_file
? 'This field is required'
: !config.project_id ||
!config.private_key ||
!config.private_key_id ||
!config.client_email ||
!config.token_uri
? 'The config file is not valid'
: ''
: '',
dataset_id: !config.dataset_id ? 'This field is required' : '',
table_id: !config.table_id ? 'This field is required' : '',
exclude_events: '',
}
: destination === 'Snowflake'
? {
account: !config.account ? 'This field is required' : '',
Expand Down Expand Up @@ -105,7 +125,7 @@ export const batchExportsEditLogic = kea<batchExportsEditLogicType>([
errors: (form) => formFields(props, form),
submit: async ({ name, destination, interval, start_at, end_at, paused, ...config }) => {
const destinationObject: BatchExportDestination =
destination == 'Postgres'
destination === 'Postgres'
? ({
type: 'Postgres',
config: config,
Expand All @@ -115,6 +135,11 @@ export const batchExportsEditLogic = kea<batchExportsEditLogicType>([
type: 'S3',
config: config,
} as unknown as BatchExportDestinationS3)
: destination === 'BigQuery'
? ({
type: 'BigQuery',
config: config,
} as unknown as BatchExportDestinationBigQuery)
: ({
type: 'Snowflake',
config: config,
Expand Down Expand Up @@ -153,6 +178,32 @@ export const batchExportsEditLogic = kea<batchExportsEditLogicType>([
}
},

setBatchExportConfigFormValue: async ({ name, value }) => {
if (name[0] === 'json_config_file' && value) {
try {
const loadedFile: string = await new Promise((resolve, reject) => {
const filereader = new FileReader()
filereader.onload = (e) => resolve(e.target?.result as string)
filereader.onerror = (e) => reject(e)
filereader.readAsText(value[0])
})
const jsonConfig = JSON.parse(loadedFile)
actions.setBatchExportConfigFormValues({
...values.batchExportConfigForm,
project_id: jsonConfig.project_id,
private_key: jsonConfig.private_key,
private_key_id: jsonConfig.private_key_id,
client_email: jsonConfig.client_email,
token_uri: jsonConfig.token_uri,
})
} catch (e) {
actions.setBatchExportConfigFormManualErrors({
json_config_file: 'The config file is not valid',
})
}
}
},

loadBatchExportConfigSuccess: ({ batchExportConfig }) => {
if (!batchExportConfig) {
return
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/scenes/batch_exports/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,9 @@ export function humanizeDestination(destination: BatchExportDestination): string
return `postgresql://${destination.config.user}:***@${destination.config.host}:${destination.config.port}/${destination.config.database}`
}

if (destination.type === 'BigQuery') {
return `bigquery:${destination.config.project_id}:${destination.config.dataset_id}:${destination.config.table_id}`
}

return 'Unknown'
}
2 changes: 1 addition & 1 deletion frontend/src/scenes/ingestion/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export function Sidebar(): JSX.Element {
{currentOrganization?.teams && currentOrganization.teams.length > 1 && (
<>
<LemonButtonWithDropdown
icon={<Lettermark name={currentOrganization?.name} />}
icon={<Lettermark name={currentOrganization.name} />}
onClick={() => toggleProjectSwitcher()}
dropdown={{
visible: isProjectSwitcherShown,
Expand Down
12 changes: 10 additions & 2 deletions frontend/src/scenes/notebooks/Nodes/NodeWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from '@tiptap/react'
import { ReactNode, useCallback, useRef } from 'react'
import clsx from 'clsx'
import { IconClose, IconDragHandle, IconLink, IconUnfoldLess, IconUnfoldMore } from 'lib/lemon-ui/icons'
import { IconClose, IconDragHandle, IconFilter, IconLink, IconUnfoldLess, IconUnfoldMore } from 'lib/lemon-ui/icons'
import { LemonButton } from '@posthog/lemon-ui'
import './NodeWrapper.scss'
import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
Expand Down Expand Up @@ -85,7 +85,7 @@ export function NodeWrapper<T extends CustomNotebookNodeAttributes>({
}
const nodeLogic = useMountedLogic(notebookNodeLogic(nodeLogicProps))
const { title, resizeable, expanded } = useValues(nodeLogic)
const { setExpanded, deleteNode } = useActions(nodeLogic)
const { setExpanded, deleteNode, setWidgetsVisible } = useActions(nodeLogic)

const [ref, inView] = useInView({ triggerOnce: true })
const contentRef = useRef<HTMLDivElement | null>(null)
Expand Down Expand Up @@ -164,6 +164,14 @@ export function NodeWrapper<T extends CustomNotebookNodeAttributes>({
/>
)}

{!!widgets.length && isEditable ? (
<LemonButton
onClick={() => setWidgetsVisible(true)}
size="small"
icon={<IconFilter />}
/>
) : null}

{isEditable && (
<LemonButton
onClick={() => deleteNode()}
Expand Down
Loading

0 comments on commit 7044c90

Please sign in to comment.