Skip to content

Commit

Permalink
Merge branch 'master' into dn-chore/remove-unused-filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
daibhin committed Aug 27, 2024
2 parents 77d46e8 + b09b469 commit ce81311
Show file tree
Hide file tree
Showing 117 changed files with 6,000 additions and 4,377 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-hog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,9 @@ jobs:
antlr | grep "Version"
npm run grammar:build && git diff --exit-code
env:
# Installing a version of ANTLR compatible with what's in Homebrew as of October 2023 (version 4.13),
# Installing a version of ANTLR compatible with what's in Homebrew as of August 2024 (version 4.13.2),
# as apt-get is quite out of date. The same version must be set in hogql_parser/pyproject.toml
ANTLR_VERSION: '4.13.1'
ANTLR_VERSION: '4.13.2'

- name: Run HogVM Python tests
if: needs.changes.outputs.hog == 'true'
Expand Down
38 changes: 37 additions & 1 deletion .github/workflows/rust-docker-build.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build rust container images
name: Build and deploy rust container images

on:
workflow_dispatch:
Expand Down Expand Up @@ -28,6 +28,9 @@ jobs:
contents: read # allow reading the repo contents
packages: write # allow push to ghcr.io

outputs:
digest: ${{ steps.docker_build.outputs.digest }}

defaults:
run:
working-directory: rust
Expand Down Expand Up @@ -91,3 +94,36 @@ jobs:

- name: Container image digest
run: echo ${{ steps.docker_build.outputs.digest }}


deploy:
name: Deploy capture-replay
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/master'
steps:
- name: get deployer token
id: deployer
uses: getsentry/action-github-app-token@v3
with:
app_id: ${{ secrets.DEPLOYER_APP_ID }}
private_key: ${{ secrets.DEPLOYER_APP_PRIVATE_KEY }}

- name: Trigger livestream deployment
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ steps.deployer.outputs.token }}
repository: PostHog/charts
event-type: commit_state_update
client-payload: |
{
"values": {
"image": {
"sha": "${{ needs.build.outputs.digest }}"
}
},
"release": "capture-replay",
"commit": ${{ toJson(github.event.head_commit) }},
"repository": ${{ toJson(github.repository) }},
"labels": []
}
12 changes: 5 additions & 7 deletions cypress/e2e/alerts.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,19 @@ describe('Alerts', () => {

const createAlert = (
name: string = 'Alert name',
email: string = '[email protected]',
lowerThreshold: string = '100',
upperThreshold: string = '200'
): void => {
cy.get('[data-attr=more-button]').click()
cy.contains('Alerts').click()
cy.contains('Manage alerts').click()
cy.contains('New alert').click()

cy.get('[data-attr=alert-name]').clear().type(name)
cy.get('[data-attr=alert-notification-targets').clear().type(email)
cy.get('[data-attr=subscribed-users').click().type('{downarrow}{enter}')
cy.get('[data-attr=alert-lower-threshold').clear().type(lowerThreshold)
cy.get('[data-attr=alert-upper-threshold').clear().type(upperThreshold)
cy.contains('Create alert').click()
cy.get('.Toastify__toast-body').should('contain', 'Alert saved')
cy.url().should('not.include', '/new')

cy.get('[aria-label="close"]').click()
Expand All @@ -38,14 +38,15 @@ describe('Alerts', () => {
cy.get('[data-attr=insight-edit-button]').click()
cy.get('[data-attr=chart-filter]').click()
cy.contains(displayType).click()
cy.get('.insight-empty-state').should('not.exist')
cy.get('[data-attr=insight-save-button]').contains('Save').click()
cy.url().should('not.include', '/edit')
}

it('Should allow create and delete an alert', () => {
cy.get('[data-attr=more-button]').click()
// Alerts should be disabled for trends represented with graphs
cy.get('[data-attr=disabled-alerts-button]').should('exist')
cy.get('[data-attr=manage-alerts-button]').should('have.attr', 'aria-disabled', 'true')

setInsightDisplayTypeAndSave('Number')

Expand All @@ -54,10 +55,8 @@ describe('Alerts', () => {

// Check the alert has the same values as when it was created
cy.get('[data-attr=more-button]').click()
cy.contains('Alerts').click()
cy.contains('Manage alerts').click()
cy.get('[data-attr=alert-list-item]').contains('Alert name').click()
cy.get('[data-attr=alert-notification-targets]').should('have.value', '[email protected]')
cy.get('[data-attr=alert-name]').should('have.value', 'Alert name')
cy.get('[data-attr=alert-lower-threshold').should('have.value', '100')
cy.get('[data-attr=alert-upper-threshold').should('have.value', '200')
Expand Down Expand Up @@ -90,7 +89,6 @@ describe('Alerts', () => {

// Assert that saving an insight in an incompatible state removes alerts
cy.get('[data-attr=more-button]').click()
cy.contains('Alerts').click()
cy.contains('Manage alerts').click()
cy.contains('Alert to be deleted because of a changed insight').should('not.exist')
})
Expand Down
4 changes: 4 additions & 0 deletions cypress/e2e/trends.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,4 +170,8 @@ describe('Trends', () => {
cy.get('[data-attr=math-monthly_active-0]').trigger('mouseenter') // Activate warning tooltip
cy.get('.Tooltip').contains('we recommend using "Unique users" here instead').should('exist')
})

it('Does not show delete button on single series insight', () => {
cy.get('[data-attr=delete-prop-filter-0]').should('not.exist')
})
})
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 19 additions & 17 deletions frontend/src/lib/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,19 @@ import { SavedSessionRecordingPlaylistsResult } from 'scenes/session-recordings/

import { getCurrentExporterData } from '~/exporter/exporterViewLogic'
import {
AlertType,
AlertTypeWrite,
DatabaseSerializedFieldType,
ErrorTrackingGroup,
QuerySchema,
QueryStatusResponse,
RecordingsQuery,
RecordingsQueryResponse,
RefreshType,
} from '~/queries/schema'
import {
ActionType,
ActivityScope,
AlertType,
AppMetricsTotalsV2Response,
AppMetricsV2RequestParams,
AppMetricsV2Response,
Expand Down Expand Up @@ -93,7 +96,6 @@ import {
SessionRecordingPlaylistType,
SessionRecordingSnapshotParams,
SessionRecordingSnapshotResponse,
SessionRecordingsResponse,
SessionRecordingType,
SharingConfigurationType,
SlackChannelType,
Expand Down Expand Up @@ -730,12 +732,12 @@ class ApiRequest {
}

// # Alerts
public alerts(teamId?: TeamType['id']): ApiRequest {
return this.projectsDetail(teamId).addPathComponent('alerts')
public alerts(id: InsightModel['id'], teamId?: TeamType['id']): ApiRequest {
return this.insight(id, teamId).addPathComponent('alerts')
}

public alert(id: AlertType['id'], teamId?: TeamType['id']): ApiRequest {
return this.alerts(teamId).addPathComponent(id)
public alert(id: AlertType['id'], insightId: InsightModel['id'], teamId?: TeamType['id']): ApiRequest {
return this.alerts(insightId, teamId).addPathComponent(id)
}

// Resource Access Permissions
Expand Down Expand Up @@ -1750,7 +1752,7 @@ const api = {
},

recordings: {
async list(params: Record<string, any>): Promise<SessionRecordingsResponse> {
async list(params: RecordingsQuery): Promise<RecordingsQueryResponse> {
return await new ApiRequest().recordings().withQueryString(toParams(params)).get()
},
async getMatchingEvents(params: string): Promise<{ results: string[] }> {
Expand Down Expand Up @@ -1838,7 +1840,7 @@ const api = {
async listPlaylistRecordings(
playlistId: SessionRecordingPlaylistType['short_id'],
params: Record<string, any> = {}
): Promise<SessionRecordingsResponse> {
): Promise<RecordingsQueryResponse> {
return await new ApiRequest()
.recordingPlaylist(playlistId)
.withAction('recordings')
Expand Down Expand Up @@ -2264,20 +2266,20 @@ const api = {
},

alerts: {
async get(alertId: AlertType['id']): Promise<AlertType> {
return await new ApiRequest().alert(alertId).get()
async get(insightId: number, alertId: AlertType['id']): Promise<AlertType> {
return await new ApiRequest().alert(alertId, insightId).get()
},
async create(data: Partial<AlertType>): Promise<AlertType> {
return await new ApiRequest().alerts().create({ data })
async create(insightId: number, data: Partial<AlertTypeWrite>): Promise<AlertType> {
return await new ApiRequest().alerts(insightId).create({ data })
},
async update(alertId: AlertType['id'], data: Partial<AlertType>): Promise<AlertType> {
return await new ApiRequest().alert(alertId).update({ data })
async update(insightId: number, alertId: AlertType['id'], data: Partial<AlertTypeWrite>): Promise<AlertType> {
return await new ApiRequest().alert(alertId, insightId).update({ data })
},
async list(insightId: number): Promise<PaginatedResponse<AlertType>> {
return await new ApiRequest().alerts().withQueryString(`insight=${insightId}`).get()
return await new ApiRequest().alerts(insightId).get()
},
async delete(alertId: AlertType['id']): Promise<void> {
return await new ApiRequest().alert(alertId).delete()
async delete(insightId: number, alertId: AlertType['id']): Promise<void> {
return await new ApiRequest().alert(alertId, insightId).delete()
},
},

Expand Down
10 changes: 9 additions & 1 deletion frontend/src/lib/components/Alerts/AlertDeletionWarning.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,16 @@ import { alertsLogic } from './alertsLogic'
export function AlertDeletionWarning(): JSX.Element | null {
const { insightProps, insight } = useValues(insightLogic)

if (!insight?.short_id) {
return null
}

const { shouldShowAlertDeletionWarning } = useValues(
alertsLogic({ insightShortId: insight.short_id!, insightLogicProps: insightProps })
alertsLogic({
insightShortId: insight.short_id,
insightId: insight.id as number,
insightLogicProps: insightProps,
})
)

if (!shouldShowAlertDeletionWarning || !insight.short_id) {
Expand Down
51 changes: 18 additions & 33 deletions frontend/src/lib/components/Alerts/AlertsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { LemonButton, LemonButtonWithDropdown } from '@posthog/lemon-ui'
import { LemonButton } from '@posthog/lemon-ui'
import { useActions, useValues } from 'kea'
import { router } from 'kea-router'
import { FEATURE_FLAGS } from 'lib/constants'
Expand All @@ -17,11 +17,11 @@ import { ManageAlerts } from './views/ManageAlerts'
export interface AlertsModalProps extends AlertsLogicProps {
isOpen: boolean
closeModal: () => void
alertId: number | 'new' | null
alertId?: string | null
}

export function AlertsModal(props: AlertsModalProps): JSX.Element {
const { closeModal, insightShortId, insightLogicProps, alertId, isOpen } = props
const { closeModal, insightId, insightShortId, insightLogicProps, alertId, isOpen } = props
const { push } = useActions(router)
const { userLoading } = useValues(userLogic)

Expand All @@ -32,14 +32,16 @@ export function AlertsModal(props: AlertsModalProps): JSX.Element {
<LemonModal onClose={closeModal} isOpen={isOpen} width={600} simple title="">
{!alertId ? (
<ManageAlerts
insightId={insightId}
insightShortId={insightShortId}
insightLogicProps={insightLogicProps}
onCancel={closeModal}
onSelect={(id) => push(urls.alert(insightShortId, id.toString()))}
onSelect={(id) => push(urls.alert(insightShortId, id ?? 'new'))}
/>
) : (
<EditAlert
id={alertId}
id={alertId === 'new' ? undefined : alertId}
insightId={insightId}
insightShortId={insightShortId}
insightLogicProps={insightLogicProps}
onCancel={() => push(urls.alerts(insightShortId))}
Expand All @@ -62,36 +64,19 @@ export function AlertsButton({ insight }: AlertsButtonProps): JSX.Element {
if (!showAlerts) {
return <></>
}
if (!areAlertsSupportedForInsight(insight.query)) {
return (
<LemonButton
data-attr="disabled-alerts-button"
disabledReason="Insights are only availabe for trends represented as a number. Change the insight representation to add alerts."
>
Alerts
</LemonButton>
)
}

return (
<LemonButtonWithDropdown
<LemonButton
data-attr="manage-alerts-button"
onClick={() => push(urls.alerts(insight.short_id!))}
fullWidth
dropdown={{
actionable: true,
closeParentPopoverOnClickInside: true,
placement: 'right-start',
overlay: (
<>
<LemonButton onClick={() => push(urls.alert(insight.short_id!, 'new'))} fullWidth>
New alert
</LemonButton>
<LemonButton onClick={() => push(urls.alerts(insight.short_id!))} fullWidth>
Manage alerts
</LemonButton>
</>
),
}}
disabledReason={
!areAlertsSupportedForInsight(insight.query)
? 'Insights are only available for trends represented as a number. Change the insight representation to add alerts.'
: undefined
}
>
Alerts
</LemonButtonWithDropdown>
Manage alerts
</LemonButton>
)
}
Loading

0 comments on commit ce81311

Please sign in to comment.