+
+ {'feature_flag' in earlyAccessFeature ? (
+
+
}
- size="small"
- onClick={() => onChange(undefined)}
- aria-label="close"
- />
+ type="secondary"
+ onClick={() =>
+ earlyAccessFeature.feature_flag &&
+ router.actions.push(
+ urls.featureFlag(earlyAccessFeature.feature_flag.id)
+ )
+ }
+ icon={ }
+ >
+ {earlyAccessFeature.feature_flag.key}
+
+
+
+ ) : (
+
A feature flag will be generated from feature name if not provided>}
+ >
+ {({ value, onChange }) => (
+
+
+ {value && (
+ }
+ size="small"
+ onClick={() => onChange(undefined)}
+ aria-label="close"
+ />
+ )}
+
)}
-
+
)}
-
- )}
- {isEditingFeature || isNewEarlyAccessFeature ? (
- <>>
- ) : (
-
-
Stage
-
-
- {earlyAccessFeature.stage}
-
-
- )}
- {isEditingFeature || isNewEarlyAccessFeature ? (
-
-
-
- ) : (
-
-
Description
-
- {earlyAccessFeature.description ? (
- earlyAccessFeature.description
- ) : (
-
No description
- )}
+ {isEditingFeature || isNewEarlyAccessFeature ? (
+ <>>
+ ) : (
+
+
Stage
+
+
+ {earlyAccessFeature.stage}
+
+
+ )}
+
+
+
+ {isEditingFeature || isNewEarlyAccessFeature ? (
+
+
+
+ ) : (
+
+
Description
+
+ {earlyAccessFeature.description ? (
+ earlyAccessFeature.description
+ ) : (
+ No description
+ )}
+
+
+ )}
- )}
- {isEditingFeature || isNewEarlyAccessFeature ? (
-
-
-
- ) : (
-
-
Documentation URL
-
- {earlyAccessFeature.documentation_url ? (
- earlyAccessFeature.documentation_url
- ) : (
- No documentation URL
- )}
-
+
+ {isEditingFeature || isNewEarlyAccessFeature ? (
+
+
+
+ ) : (
+
+
Documentation URL
+
+ {earlyAccessFeature.documentation_url ? (
+
+ {earlyAccessFeature.documentation_url}
+
+ ) : (
+ No documentation URL
+ )}
+
+
+ )}
- )}
+
{!isEditingFeature && !isNewEarlyAccessFeature && 'id' in earlyAccessFeature && (
-
+ <>
+
+
+
+
Users
+
+ When a user opts in or out of the feature they will be listed here. You can choose
+ to{' '}
+
+ implement your own opt-in interface or use our provided app.
+
+
+
+
}
+ type="secondary"
+ >
+ Implement public opt-in
+
+
-
+ >
)}
+
+ {'id' in earlyAccessFeature ? (
+
+ ) : null}
)
}
@@ -326,10 +370,8 @@ function featureFlagEnrolmentFilter(earlyAccessFeature: EarlyAccessFeatureType,
}
export function PersonList({ earlyAccessFeature }: PersonListProps): JSX.Element {
- const { implementOptInInstructionsModal, activeTab } = useValues(earlyAccessFeatureLogic)
- const { toggleImplementOptInInstructionsModal, setActiveTab } = useActions(earlyAccessFeatureLogic)
-
- const { featureFlag } = useValues(featureFlagLogic({ id: earlyAccessFeature.feature_flag.id || 'link' }))
+ const { activeTab } = useValues(earlyAccessFeatureLogic)
+ const { setActiveTab } = useActions(earlyAccessFeatureLogic)
const key = '$feature_enrollment/' + earlyAccessFeature.feature_flag.key
@@ -354,14 +396,6 @@ export function PersonList({ earlyAccessFeature }: PersonListProps): JSX.Element
value: ['true'],
},
]}
- emptyState={
-
- No manual opt-ins. Manually opted-in people will appear here. Start by{' '}
-
- implementing public opt-in
-
-
- }
/>
>
),
@@ -380,113 +414,44 @@ export function PersonList({ earlyAccessFeature }: PersonListProps): JSX.Element
value: ['false'],
},
]}
- emptyState={
-
- No manual opt-outs. Manually opted-out people will appear here. Start by{' '}
-
- implementing public opt-out
-
-
- }
/>
),
},
]}
/>
-
-
>
)
}
interface PersonsTableByFilterProps {
properties: PersonPropertyFilter[]
- emptyState?: JSX.Element
recordingsFilters: Partial
}
-export function PersonsTableByFilter(props: PersonsTableByFilterProps): JSX.Element {
- const personsLogicProps: PersonsLogicProps = {
- cohort: undefined,
- syncWithUrl: false,
- fixedProperties: props.properties,
- }
+function PersonsTableByFilter({ recordingsFilters, properties }: PersonsTableByFilterProps): JSX.Element {
+ const [query, setQuery] = useState({
+ kind: NodeKind.DataTableNode,
+ source: {
+ kind: NodeKind.PersonsNode,
+ fixedProperties: properties,
+ },
+ full: true,
+ propertiesViaUrl: false,
+ })
return (
-
-
-
- )
-}
-
-interface PersonsTableByFilterComponentProps {
- emptyState?: JSX.Element
- recordingsFilters: Partial
-}
-
-function PersonsTableByFilterComponent({
- emptyState,
- recordingsFilters,
-}: PersonsTableByFilterComponentProps): JSX.Element {
- const { toggleImplementOptInInstructionsModal } = useActions(earlyAccessFeatureLogic)
-
- const { persons, personsLoading, listFilters } = useValues(personsLogic)
- const { loadPersons, setListFilters } = useActions(personsLogic)
-
- return (
-
-
-
+
+ {/* NOTE: This is a bit of a placement hack - ideally we would be able to add it to the Query */}
+
+
+ View recordings
+
-
-
{
- setListFilters({ properties })
- loadPersons()
- }}
- endpoint="person"
- taxonomicGroupTypes={[TaxonomicFilterGroupType.PersonProperties]}
- showConditionBadge
- />
-
- }
- >
- Implement public opt-in
-
- {
- router.actions.push(urls.replay(ReplayTabs.Recent, recordingsFilters))
- }}
- type="secondary"
- disabledReason={
- personsLoading ? 'Loading…' : persons.results.length === 0 ? 'No users to view' : undefined
- }
- >
- View recordings
-
-
-
-
loadPersons(persons.previous)}
- loadNext={() => loadPersons(persons.next)}
- compact={true}
- extraColumns={[]}
- emptyState={emptyState}
- />
+
)
}
diff --git a/frontend/src/scenes/early-access-features/InstructionsModal.tsx b/frontend/src/scenes/early-access-features/InstructionsModal.tsx
index c0b05f009d1f7..61c87c650a8c0 100644
--- a/frontend/src/scenes/early-access-features/InstructionsModal.tsx
+++ b/frontend/src/scenes/early-access-features/InstructionsModal.tsx
@@ -7,12 +7,12 @@ import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
import { FeatureFlagType } from '~/types'
interface InstructionsModalProps {
- featureFlag: FeatureFlagType
+ flag: FeatureFlagType['key']
visible: boolean
onClose: () => void
}
-export function InstructionsModal({ onClose, visible, featureFlag }: InstructionsModalProps): JSX.Element {
+export function InstructionsModal({ onClose, visible, flag }: InstructionsModalProps): JSX.Element {
const { preflight } = useValues(preflightLogic)
const getCloudPanels = (): JSX.Element => (
@@ -38,12 +38,12 @@ export function InstructionsModal({ onClose, visible, featureFlag }: Instruction
Opt user in
-
+
Opt user out
-
+
Retrieve Previews
@@ -61,12 +61,12 @@ export function InstructionsModal({ onClose, visible, featureFlag }: Instruction
Opt user in
-
+
Opt user out
-
+
Retrieve Previews
@@ -91,19 +91,19 @@ export function InstructionsModal({ onClose, visible, featureFlag }: Instruction
)
}
-function FeatureEnrollInstructions({ featureFlag }: { featureFlag: FeatureFlagType }): JSX.Element {
+function FeatureEnrollInstructions({ flag }: { flag: string }): JSX.Element {
return (
- {`posthog.updateEarlyAccessFeatureEnrollment("${featureFlag.key}", true)
+ {`posthog.updateEarlyAccessFeatureEnrollment("${flag}", true)
`}
)
}
-function FeatureUnenrollInstructions({ featureFlag }: { featureFlag: FeatureFlagType }): JSX.Element {
+function FeatureUnenrollInstructions({ flag }: { flag: string }): JSX.Element {
return (
- {`posthog.updateEarlyAccessFeatureEnrollment("${featureFlag.key}", false)
+ {`posthog.updateEarlyAccessFeatureEnrollment("${flag}", false)
`}
)
diff --git a/frontend/src/scenes/persons/PersonsTable.tsx b/frontend/src/scenes/persons/PersonsTable.tsx
deleted file mode 100644
index 05ecbccc5233b..0000000000000
--- a/frontend/src/scenes/persons/PersonsTable.tsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import { IconTrash } from '@posthog/icons'
-import { LemonButton } from '@posthog/lemon-ui'
-import { useActions } from 'kea'
-import { CopyToClipboardInline } from 'lib/components/CopyToClipboard'
-import { PropertiesTable } from 'lib/components/PropertiesTable'
-import { TZLabel } from 'lib/components/TZLabel'
-import { LemonTable, LemonTableColumn, LemonTableColumns } from 'lib/lemon-ui/LemonTable'
-import { PersonDeleteModal } from 'scenes/persons/PersonDeleteModal'
-import { personDeleteModalLogic } from 'scenes/persons/personDeleteModalLogic'
-import { personsLogic } from 'scenes/persons/personsLogic'
-
-import { PersonType, PropertyDefinitionType } from '~/types'
-
-import { PersonDisplay } from './PersonDisplay'
-
-interface PersonsTableType {
- people: PersonType[]
- loading?: boolean
- hasPrevious?: boolean
- hasNext?: boolean
- loadPrevious?: () => void
- loadNext?: () => void
- compact?: boolean
- extraColumns?: LemonTableColumns
- emptyState?: JSX.Element
-}
-
-export function PersonsTable({
- people,
- loading = false,
- hasPrevious,
- hasNext,
- loadPrevious,
- loadNext,
- compact,
- extraColumns,
- emptyState,
-}: PersonsTableType): JSX.Element {
- const { showPersonDeleteModal } = useActions(personDeleteModalLogic)
- const { loadPersons } = useActions(personsLogic)
-
- const columns: LemonTableColumns = [
- {
- title: 'Person',
- key: 'person',
- render: function Render(_, person: PersonType) {
- return
- },
- },
- ...(!compact
- ? ([
- {
- title: 'ID',
- key: 'id',
- render: function Render(_, person: PersonType) {
- return (
-
- {person.distinct_ids.length && (
-
- {person.distinct_ids[0]}
-
- )}
-
- )
- },
- },
- {
- title: 'First seen',
- dataIndex: 'created_at',
- render: function Render(created_at: PersonType['created_at']) {
- return created_at ? : <>>
- },
- },
- {
- render: function Render(_, person: PersonType) {
- return (
- showPersonDeleteModal(person, () => loadPersons())}
- icon={ }
- status="danger"
- size="small"
- />
- )
- },
- },
- ] as Array>)
- : []),
- ...(extraColumns || []),
- ]
-
- return (
- <>
- {
- loadNext?.()
- window.scrollTo(0, 0)
- }
- : undefined,
- onBackward: hasPrevious
- ? () => {
- loadPrevious?.()
- window.scrollTo(0, 0)
- }
- : undefined,
- }}
- expandable={{
- expandedRowRender: function RenderPropertiesTable({ properties }) {
- return Object.keys(properties).length ? (
-
- ) : (
- 'This person has no properties.'
- )
- },
- }}
- dataSource={people}
- emptyState={emptyState ? emptyState : 'No persons'}
- nouns={['person', 'persons']}
- />
-
- >
- )
-}