-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* frontend form * list / create records * move settings * fix types * add fields * new fields & delete * better states * Update UI snapshots for `chromium` (1) * basic task * background task * Hide proxy settings behind feature flag * text color * Update UI snapshots for `chromium` (1) * Squash migrations * Add created_at/update_at/created_by * form complete state * move env vars * cleanup * Use env var for target cname * call create in celery task * fix dns resolver import * frontend polling * order queryset * tweaks * Only save on change * Update UI snapshots for `chromium` (1) * only create proxy task if is_cloud * hide settings if not cloud * Update query snapshots * Update UI snapshots for `chromium` (1) * cloud or dev * spacing * deleting * save docker images * add final status * update manifest * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * fix celery task * Fix org_id on proxy record * isDomain not isUrl * fix destroy kwargs * fix help text * domain check * frontend form * list / create records * move settings * fix types * add fields * new fields & delete * better states * Update UI snapshots for `chromium` (1) * basic task * background task * text color * Hide proxy settings behind feature flag * form complete state * Update UI snapshots for `chromium` (1) * Squash migrations * Add created_at/update_at/created_by * move env vars * cleanup * frontend polling * Use env var for target cname * call create in celery task * fix dns resolver import * order queryset * hide settings if not cloud * tweaks * Only save on change * Update UI snapshots for `chromium` (1) * only create proxy task if is_cloud * cloud or dev * Update query snapshots * Update UI snapshots for `chromium` (1) * spacing * deleting * add final status * save docker images * update manifest * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * fix celery task * Fix org_id on proxy record * isDomain not isUrl * domain check * fix destroy kwargs * fix help text * Update UI snapshots for `chromium` (2) * Update UI snapshots for `chromium` (1) * Update UI snapshots for `chromium` (2) * Update UI snapshots for `chromium` (1) * fix code quality issues * code quality * fix merge * spinner spacing * remove unused selectors * Update UI snapshots for `chromium` (1) --------- Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Frank Hamand <frankhamand@gmail.com>
- Loading branch information
1 parent
de0b78b
commit de69ab8
Showing
20 changed files
with
479 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file modified
BIN
-1.86 KB
(87%)
...end/__snapshots__/exporter-exporter--funnel-historical-trends-insight--dark.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-1.9 KB
(86%)
...nd/__snapshots__/exporter-exporter--funnel-historical-trends-insight--light.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified
BIN
-437 Bytes
(100%)
...snapshots__/scenes-app-insights--funnel-top-to-bottom-breakdown-edit--light.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import { IconEllipsis, IconPlus } from '@posthog/icons' | ||
import { | ||
LemonBanner, | ||
LemonButton, | ||
LemonInput, | ||
LemonMenu, | ||
LemonTable, | ||
LemonTableColumns, | ||
Spinner, | ||
} from '@posthog/lemon-ui' | ||
import clsx from 'clsx' | ||
import { useActions, useValues } from 'kea' | ||
import { Form } from 'kea-forms' | ||
import { CodeSnippet, Language } from 'lib/components/CodeSnippet' | ||
import { LemonField } from 'lib/lemon-ui/LemonField' | ||
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' | ||
|
||
import { proxyLogic, ProxyRecord } from './proxyLogic' | ||
|
||
export function Proxy(): JSX.Element { | ||
const { isCloudOrDev } = useValues(preflightLogic) | ||
const { formState, proxyRecords } = useValues(proxyLogic) | ||
const { showForm, deleteRecord } = useActions(proxyLogic) | ||
|
||
if (!isCloudOrDev) { | ||
return <LemonBanner type="warning">Using a reverse proxy only works in PostHog Cloud</LemonBanner> | ||
} | ||
|
||
const columns: LemonTableColumns<ProxyRecord> = [ | ||
{ | ||
title: 'Domain', | ||
dataIndex: 'domain', | ||
}, | ||
{ | ||
title: 'Status', | ||
dataIndex: 'status', | ||
render: function RenderStatus(status) { | ||
return ( | ||
<div className="space-x-1"> | ||
{status === 'issuing' && <Spinner />} | ||
<span | ||
className={clsx( | ||
'capitalize', | ||
status === 'valid' | ||
? 'text-success' | ||
: status == 'erroring' | ||
? 'text-danger' | ||
: 'text-warning' | ||
)} | ||
> | ||
{status} | ||
</span> | ||
</div> | ||
) | ||
}, | ||
}, | ||
{ | ||
title: 'Actions', | ||
render: function Render(_, { id, status }) { | ||
return ( | ||
status != 'deleting' && ( | ||
<LemonMenu | ||
items={[ | ||
{ | ||
label: 'Delete', | ||
status: 'danger', | ||
onClick: () => deleteRecord(id), | ||
}, | ||
]} | ||
> | ||
<LemonButton size="xsmall" icon={<IconEllipsis />} /> | ||
</LemonMenu> | ||
) | ||
) | ||
}, | ||
}, | ||
] | ||
|
||
return ( | ||
<div className="space-y-2"> | ||
<LemonTable columns={columns} dataSource={proxyRecords} /> | ||
{formState === 'collapsed' ? ( | ||
<LemonButton onClick={showForm} type="secondary" icon={<IconPlus />}> | ||
Add domain | ||
</LemonButton> | ||
) : ( | ||
<CreateRecordForm /> | ||
)} | ||
</div> | ||
) | ||
} | ||
|
||
function CreateRecordForm(): JSX.Element { | ||
const { formState, proxyRecordsLoading } = useValues(proxyLogic) | ||
const { collapseForm } = useActions(proxyLogic) | ||
|
||
return ( | ||
<div className="bg-bg-light rounded border p-2 space-y-2"> | ||
{formState == 'active' ? ( | ||
<Form logic={proxyLogic} formKey="createRecord" enableFormOnSubmit className="w-full space-y-2"> | ||
<LemonField name="domain"> | ||
<LemonInput | ||
autoFocus | ||
placeholder="Enter a domain (e.g. ph.mydomain.com)" | ||
data-attr="domain-input" | ||
/> | ||
</LemonField> | ||
<div className="flex justify-end gap-2"> | ||
<LemonButton | ||
type="secondary" | ||
onClick={collapseForm} | ||
disabledReason={proxyRecordsLoading ? 'Saving' : undefined} | ||
> | ||
Cancel | ||
</LemonButton> | ||
<LemonButton | ||
htmlType="submit" | ||
type="primary" | ||
data-attr="domain-save" | ||
loading={proxyRecordsLoading} | ||
> | ||
Add | ||
</LemonButton> | ||
</div> | ||
</Form> | ||
) : ( | ||
<> | ||
<div className="text-xl font-semibold leading-tight">Almost there</div> | ||
<div> | ||
You need to set the <b>CNAME</b> record on your DNS provider: | ||
</div> | ||
<CodeSnippet language={Language.HTTP}>sdfghgfdsdfghgfdsw.com</CodeSnippet> | ||
<div className="flex justify-end"> | ||
<LemonButton onClick={collapseForm} type="primary"> | ||
Done | ||
</LemonButton> | ||
</div> | ||
</> | ||
)} | ||
</div> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import { actions, afterMount, beforeUnmount, connect, kea, listeners, path, reducers } from 'kea' | ||
import { forms } from 'kea-forms' | ||
import { loaders } from 'kea-loaders' | ||
import api from 'lib/api' | ||
import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast' | ||
import { isDomain } from 'lib/utils' | ||
import { organizationLogic } from 'scenes/organizationLogic' | ||
|
||
import type { proxyLogicType } from './proxyLogicType' | ||
|
||
export type ProxyRecord = { | ||
id: string | ||
domain: string | ||
status: 'waiting' | 'issuing' | 'valid' | 'erroring' | 'deleting' | ||
cname_target: string | ||
} | ||
|
||
export type FormState = 'collapsed' | 'active' | 'complete' | ||
|
||
export const proxyLogic = kea<proxyLogicType>([ | ||
path(['scenes', 'project', 'Settings', 'proxyLogic']), | ||
connect({ values: [organizationLogic, ['currentOrganization']] }), | ||
actions(() => ({ | ||
collapseForm: true, | ||
showForm: true, | ||
completeForm: true, | ||
})), | ||
reducers(() => ({ | ||
formState: [ | ||
'collapsed' as FormState, | ||
{ showForm: () => 'active', collapseForm: () => 'collapsed', completeForm: () => 'complete' }, | ||
], | ||
})), | ||
loaders(({ values, actions }) => ({ | ||
proxyRecords: { | ||
__default: [] as ProxyRecord[], | ||
loadRecords: async () => { | ||
return await api.get(`api/organizations/${values.currentOrganization?.id}/proxy_records`) | ||
}, | ||
createRecord: async ({ domain }: { domain: string }) => { | ||
const response = await api.create(`api/organizations/${values.currentOrganization?.id}/proxy_records`, { | ||
domain, | ||
}) | ||
lemonToast.success('Record created') | ||
actions.completeForm() | ||
return response | ||
}, | ||
deleteRecord: async (id: ProxyRecord['id']) => { | ||
const response = await api.delete( | ||
`api/organizations/${values.currentOrganization?.id}/proxy_records/${id}` | ||
) | ||
return response | ||
}, | ||
}, | ||
})), | ||
listeners(({ actions, values, cache }) => ({ | ||
collapseForm: () => actions.loadRecords(), | ||
deleteRecordFailure: () => actions.loadRecords(), | ||
loadRecordsSuccess: () => { | ||
const shouldRefresh = values.proxyRecords.some((r) => ['waiting', 'issuing', 'deleting'].includes(r.status)) | ||
if (shouldRefresh) { | ||
cache.refreshTimeout = setTimeout(() => { | ||
actions.loadRecords() | ||
}, 5000) | ||
} | ||
}, | ||
})), | ||
forms(({ actions }) => ({ | ||
createRecord: { | ||
defaults: { domain: '' }, | ||
errors: ({ domain }: { domain: string }) => ({ | ||
domain: !isDomain('http://' + domain) | ||
? 'Do not include the protocol e.g. https://' | ||
: domain.includes('*') | ||
? 'Domains cannot include wildcards' | ||
: undefined, | ||
}), | ||
submit: ({ domain }) => { | ||
actions.createRecord({ domain }) | ||
}, | ||
}, | ||
})), | ||
afterMount(({ actions }) => { | ||
actions.loadRecords() | ||
}), | ||
beforeUnmount(({ cache }) => { | ||
if (cache.refreshTimeout) { | ||
clearTimeout(cache.refreshTimeout) | ||
} | ||
}), | ||
]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
from django.conf import settings | ||
from rest_framework import serializers | ||
from rest_framework.viewsets import ModelViewSet | ||
|
||
from posthog.api.routing import TeamAndOrgViewSetMixin | ||
from posthog.models import ProxyRecord | ||
from posthog.permissions import OrganizationAdminWritePermissions | ||
from rest_framework.response import Response | ||
|
||
|
||
class ProxyRecordSerializer(serializers.ModelSerializer): | ||
class Meta: | ||
model = ProxyRecord | ||
fields = ( | ||
"id", | ||
"domain", | ||
"target_cname", | ||
"status", | ||
"created_at", | ||
"updated_at", | ||
"created_by", | ||
) | ||
read_only_fields = ("target_cname", "created_at", "created_by", "status") | ||
|
||
|
||
class ProxyRecordViewset(TeamAndOrgViewSetMixin, ModelViewSet): | ||
scope_object = "organization" | ||
serializer_class = ProxyRecordSerializer | ||
permission_classes = [OrganizationAdminWritePermissions] | ||
|
||
def list(self, request, *args, **kwargs): | ||
queryset = self.organization.proxy_records.order_by("-created_at") | ||
serializer = self.get_serializer(queryset, many=True) | ||
return Response(serializer.data) | ||
|
||
def create(self, request, *args, **kwargs): | ||
domain = request.data.get("domain") | ||
queryset = self.organization.proxy_records.order_by("-created_at") | ||
queryset.create( | ||
organization_id=self.organization.id, | ||
created_by=request.user, | ||
domain=domain, | ||
target_cname=settings.PROXY_TARGET_CNAME, | ||
) | ||
serializer = self.get_serializer(queryset, many=True) | ||
return Response(serializer.data) | ||
|
||
def destroy(self, request, *args, pk=None, **kwargs): | ||
queryset = self.organization.proxy_records.order_by("-created_at") | ||
record = queryset.get(id=pk) | ||
|
||
if record: | ||
record.status = ProxyRecord.Status.DELETING | ||
record.save() | ||
|
||
serializer = self.get_serializer(queryset, many=True) | ||
return Response(serializer.data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.