diff --git a/.agents/skills/writing-kea-logics/SKILL.md b/.agents/skills/writing-kea-logics/SKILL.md index 992bee4550fc..c82afb27bc20 100644 --- a/.agents/skills/writing-kea-logics/SKILL.md +++ b/.agents/skills/writing-kea-logics/SKILL.md @@ -44,9 +44,9 @@ If your work overlaps it, read the companion skill first. action that changed the value instead. See [references/reacting-to-changes.md](references/reacting-to-changes.md). -4. **Generated types are the contract.** Every logic has an auto-generated - `*LogicType.ts` next to it. Import with `import type` and pass it as the kea type - parameter. Never edit the generated file. +4. **Generated types are the contract.** Every logic has an inline generated + `MakeLogicType` block above its `kea()` call. Import a logic type from the logic + source file, never from a separate `*LogicType.ts` file. 5. **Resources that need cleanup go through `cache.disposables`.** See the [using-kea-disposables](../using-kea-disposables/SKILL.md) skill. @@ -131,12 +131,23 @@ today" — they age, so the pattern itself is the source of truth. ## Types and typegen ```ts -import type { fooLogicType } from './fooLogicType' +import { MakeLogicType, kea } from 'kea' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface fooLogicValues { + name: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface fooLogicActions { + setName: (name: string) => { name: string } +} + +export type fooLogicType = MakeLogicType export const fooLogic = kea([...]) ``` -Generated `*LogicType.ts` files are produced by `kea-typegen` (we use the -`3.6.2-leakfix.x` private fork). Commands: +Inline type blocks are produced by `kea-typegen` 3.8.2. Commands: - `pnpm --filter=@posthog/frontend typegen:watch` — watch mode while writing logics - `pnpm --filter=@posthog/frontend typegen:write` — one-shot write @@ -149,19 +160,19 @@ on a single logic, scope both to that file: ```sh # Regenerate the type for one logic -pnpm --filter=@posthog/frontend exec kea-typegen write \ - -f frontend/src/scenes/foo/fooLogic.ts -r ./frontend/src +pnpm --filter=@posthog/frontend typegen:file frontend/src/scenes/foo/fooLogic.ts # Type-check just that file (and its imports — fast, but won't catch downstream # breakage in other files that consume the new types) -pnpm --filter=@posthog/frontend exec tsc --noEmit \ +pnpm --filter=@posthog/frontend exec tsgo --noEmit \ frontend/src/scenes/foo/fooLogic.ts ``` Use this loop while writing the logic; run the full `typegen:check` / `typescript:check` once at the end to confirm nothing else broke. -Never edit a `*LogicType.ts` file by hand — change the logic and re-run typegen. +Do not create or import a separate `*LogicType.ts` file. Change the logic and re-run +typegen so the inline generated block stays authoritative. For keyed logics, annotate the export explicitly: `export const fooLogic: LogicWrapper = kea([...])`. diff --git a/.agents/skills/writing-kea-logics/references/anti-patterns.md b/.agents/skills/writing-kea-logics/references/anti-patterns.md index 65512dc38cae..17262c3580f5 100644 --- a/.agents/skills/writing-kea-logics/references/anti-patterns.md +++ b/.agents/skills/writing-kea-logics/references/anti-patterns.md @@ -343,10 +343,10 @@ That's a `forms` builder waiting to be written. ## Types -### Editing `*LogicType.ts` by hand +### Creating or importing `*LogicType.ts` -It's regenerated by `kea-typegen`. Your changes will be wiped. Change the logic and -re-run typegen. +Logic types are generated inline in the logic source. A separate type file will drift +or be deleted by typegen. Import the type from the logic source and re-run typegen. ### Importing the runtime logic when you only need its type diff --git a/.kearc b/.kearc index d4ae51476b54..c097318ad2a3 100644 --- a/.kearc +++ b/.kearc @@ -3,5 +3,5 @@ "rootPath": "./frontend/src", "typesPath": "./frontend/src", "writePaths": true, - "inlinePaths": ["./frontend/src/scenes/notebooks"] + "inline": true } diff --git a/frontend/package.json b/frontend/package.json index a25277228b1e..7b2ca3138a55 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -335,7 +335,7 @@ "jest-environment-jsdom": "^29.3.1", "jest-image-snapshot": "^6.1.0", "jest-junit": "^16.0.0", - "kea-typegen": "3.8.2", + "kea-typegen": "3.8.3", "less": "^3.12.2", "lint-staged": "catalog:", "mockdate": "^3.0.5", diff --git a/frontend/src/exporter/ExporterLogin.tsx b/frontend/src/exporter/ExporterLogin.tsx index a2a8d51095c0..e9e2db8c0891 100644 --- a/frontend/src/exporter/ExporterLogin.tsx +++ b/frontend/src/exporter/ExporterLogin.tsx @@ -1,8 +1,9 @@ import '../scenes/authentication/login/Login.scss' import clsx from 'clsx' -import { actions, kea, path, reducers, useValues } from 'kea' +import { MakeLogicType, actions, kea, path, reducers, useValues } from 'kea' import { Form, forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { BridgePage } from 'lib/components/BridgePage/BridgePage' import { LemonBanner } from 'lib/lemon-ui/LemonBanner' @@ -12,12 +13,85 @@ import { LemonInput } from 'lib/lemon-ui/LemonInput' import { ERROR_MESSAGES } from 'scenes/authentication/shared/loginErrorMessages' import { SupportModalButton } from 'scenes/authentication/shared/SupportModalButton' -import type { loginLogicType } from './ExporterLoginType' - export interface LoginForm { password: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface loginLogicValues { + generalError: { + code: string + detail: string + } | null + isLoginSubmitting: boolean + isLoginValid: boolean + isSuccess: boolean + login: LoginForm + loginAllErrors: Record + loginChanged: boolean + loginErrors: DeepPartialMap + loginHasErrors: boolean + loginManualErrors: Record + loginTouched: boolean + loginTouches: Record + loginValidationErrors: DeepPartialMap + showLoginErrors: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface loginLogicActions { + clearGeneralError: () => { + value: true + } + resetLogin: (values?: LoginForm) => { + values?: LoginForm + } + setGeneralError: ( + code: string, + detail: string + ) => { + code: string + detail: string + } + setLoginManualErrors: (errors: Record) => { + errors: Record + } + setLoginValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setLoginValues: (values: DeepPartial) => { + values: DeepPartial + } + setSuccess: () => { + value: true + } + submitLogin: () => { + value: boolean + } + submitLoginFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitLoginRequest: (login: LoginForm) => { + login: LoginForm + } + submitLoginSuccess: (login: LoginForm) => { + login: LoginForm + } + touchLoginField: (key: string) => { + key: string + } +} + +export type loginLogicType = MakeLogicType + export const loginLogic = kea([ path(['exporter', 'ExporterLogin']), actions({ diff --git a/frontend/src/exporter/exporterViewLogic.ts b/frontend/src/exporter/exporterViewLogic.ts index af16e6e9ff45..25a554ef9325 100644 --- a/frontend/src/exporter/exporterViewLogic.ts +++ b/frontend/src/exporter/exporterViewLogic.ts @@ -1,14 +1,70 @@ -import { actions, afterMount, connect, kea, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, props, reducers, selectors } from 'kea' import { heatmapDataLogic } from 'lib/components/heatmaps/heatmapDataLogic' -import type { exporterViewLogicType } from './exporterViewLogicType' +import type { HrefMatchType } from '../lib/components/heatmaps/heatmapDataLogic' +import type { CommonFilters, HeatmapFilters, HeatmapFixedPositionMode } from '../lib/components/heatmaps/types' import { ExportType, ExportedData } from './types' const isUrlPattern = (url: string): boolean => { return /[*+?^${}()|[\]\\]/.test(url) } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface exporterViewLogicValues { + exportedData: ExportedData + isLoading: boolean + screenshotUrl: string | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface exporterViewLogicActions { + setCommonFilters: (filters: CommonFilters) => { + filters: CommonFilters + } // heatmapDataLogic + setHeatmapColorPalette: (palette: string | null) => { + palette: string | null + } // heatmapDataLogic + setHeatmapFilters: (filters: HeatmapFilters) => { + filters: HeatmapFilters + } // heatmapDataLogic + setHeatmapFixedPositionMode: (mode: HeatmapFixedPositionMode) => { + mode: HeatmapFixedPositionMode + } // heatmapDataLogic + setHref: (href: string) => { + href: string + } // heatmapDataLogic + setHrefMatchType: (matchType: HrefMatchType) => { + matchType: HrefMatchType + } // heatmapDataLogic + setWindowWidthOverride: (widthOverride: number | null) => { + widthOverride: number | null + } // heatmapDataLogic + fetchScreenshotUrl: () => { + value: true + } + setIsLoading: (isLoading: boolean) => { + isLoading: boolean + } + setScreenshotUrl: (screenshotUrl: string) => { + screenshotUrl: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface exporterViewLogicMeta { + __keaTypeGenInternalSelectorTypes: { + exportedData: (arg: ExportedData) => ExportedData + } +} + +export type exporterViewLogicType = MakeLogicType< + exporterViewLogicValues, + exporterViewLogicActions, + ExportedData, + exporterViewLogicMeta +> + // This is a simple logic that is mounted by the Exporter view and then can be found by any nested callers // This simplifies passing props everywhere. // E.g. api.ts uses this to add the sharing_access_token diff --git a/frontend/src/kea-disposables.test.ts b/frontend/src/kea-disposables.test.ts index 4b2e87c4fe74..43c5cbaec21e 100644 --- a/frontend/src/kea-disposables.test.ts +++ b/frontend/src/kea-disposables.test.ts @@ -1,9 +1,7 @@ -import { kea, path } from 'kea' +import { MakeLogicType, kea, path } from 'kea' import { initKeaTests } from '~/test/init' -import type { logicType } from './kea-disposables.testType' - // Helper: trigger visibilitychange after mutating document.hidden const setHidden = (hidden: boolean): void => { Object.defineProperty(document, 'hidden', { configurable: true, get: () => hidden }) @@ -14,6 +12,9 @@ const setHidden = (hidden: boolean): void => { document.dispatchEvent(new Event('visibilitychange')) } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export type logicType = MakeLogicType<{}, {}> + describe('disposablesPlugin', () => { let logic: ReturnType> let setupCalls: number diff --git a/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx b/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx index 067d8a6b3b35..d953bd941ee1 100644 --- a/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx +++ b/frontend/src/layout/FeaturePreviews/featurePreviewsLogic.tsx @@ -1,4 +1,4 @@ -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { EarlyAccessFeature, posthog } from 'posthog-js' @@ -14,7 +14,10 @@ import { userLogic } from 'scenes/userLogic' import { ProductIntentContext, ProductKey } from '~/queries/schema/schema-general' -import type { featurePreviewsLogicType } from './featurePreviewsLogicType' +import type { SupportFormFields } from '../../lib/components/Support/supportLogic' +import type { FeatureFlagsSet } from '../../lib/logic/featureFlagLogic' +import type { ProductCrossSellProperties } from '../../lib/utils/product-intents' +import type { UserType } from '../../types' export interface EnrichedEarlyAccessFeature extends Omit { flagKey: string @@ -24,6 +27,105 @@ export interface EnrichedEarlyAccessFeature extends Omit() +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface featurePreviewsLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + user: UserType | null // userLogic + activeFeedbackFlagKey: string | null + activeFeedbackFlagKeyLoading: boolean + conceptEnrollments: Record + earlyAccessFeatures: EnrichedEarlyAccessFeature[] + filteredEarlyAccessFeatures: EnrichedEarlyAccessFeature[] + rawEarlyAccessFeatures: EarlyAccessFeature[] + rawEarlyAccessFeaturesLoading: boolean + searchTerm: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface featurePreviewsLogicActions { + submitSupportTicket: (form: SupportFormFields) => SupportFormFields // supportLogic + addProductIntentForCrossSell: (properties: ProductCrossSellProperties) => ProductCrossSellProperties // teamLogic + beginEarlyAccessFeatureFeedback: (flagKey: string) => { + flagKey: string + } + cancelEarlyAccessFeatureFeedback: () => { + value: true + } + copyExternalFeaturePreviewLink: (flagKey: string) => { + flagKey: string + } + loadEarlyAccessFeatures: () => any + loadEarlyAccessFeaturesFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadEarlyAccessFeaturesSuccess: ( + rawEarlyAccessFeatures: EarlyAccessFeature[], + payload?: any + ) => { + rawEarlyAccessFeatures: EarlyAccessFeature[] + payload?: any + } + setSearchTerm: (searchTerm: string) => { + searchTerm: string + } + submitEarlyAccessFeatureFeedback: (message: string) => { + message: string + } + submitEarlyAccessFeatureFeedbackFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + submitEarlyAccessFeatureFeedbackSuccess: ( + activeFeedbackFlagKey: string | null, + payload?: { + message: string + } + ) => { + activeFeedbackFlagKey: string | null + payload?: { + message: string + } + } + updateEarlyAccessFeatureEnrollment: ( + flagKey: string, + enabled: boolean, + stage?: string + ) => { + enabled: boolean + flagKey: string + stage: string | undefined + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface featurePreviewsLogicMeta { + __keaTypeGenInternalSelectorTypes: { + earlyAccessFeatures: ( + rawEarlyAccessFeatures: EarlyAccessFeature[], + featureFlags: FeatureFlagsSet, + conceptEnrollments: Record + ) => EnrichedEarlyAccessFeature[] + filteredEarlyAccessFeatures: ( + earlyAccessFeatures: EnrichedEarlyAccessFeature[], + searchTerm: string + ) => EnrichedEarlyAccessFeature[] + } +} + +export type featurePreviewsLogicType = MakeLogicType< + featurePreviewsLogicValues, + featurePreviewsLogicActions, + Record, + featurePreviewsLogicMeta +> + export const featurePreviewsLogic = kea([ path(['layout', 'FeaturePreviews', 'featurePreviewsLogic']), connect(() => ({ @@ -154,7 +256,11 @@ export const featurePreviewsLogic = kea([ selectors({ earlyAccessFeatures: [ (s) => [s.rawEarlyAccessFeatures, s.featureFlags, s.conceptEnrollments], - (rawEarlyAccessFeatures, featureFlags, conceptEnrollments): EnrichedEarlyAccessFeature[] => { + ( + rawEarlyAccessFeatures: EarlyAccessFeature[], + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + conceptEnrollments: Record + ): EnrichedEarlyAccessFeature[] => { // posthog-js persists enrollment as person properties in localStorage, // which survives page reloads even though concept-stage flags evaluate // to false on the server. diff --git a/frontend/src/layout/globalModalsLogic.ts b/frontend/src/layout/globalModalsLogic.ts index 3f026a48b0d2..d6443d1e4f30 100644 --- a/frontend/src/layout/globalModalsLogic.ts +++ b/frontend/src/layout/globalModalsLogic.ts @@ -1,8 +1,30 @@ -import { actions, kea, path, reducers } from 'kea' +import { MakeLogicType, actions, kea, path, reducers } from 'kea' import { bindModalToUrl } from 'lib/logic/bindModalToUrl' -import type { globalModalsLogicType } from './globalModalsLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface globalModalsLogicValues { + isCreateOrganizationModalShown: boolean + isCreateProjectModalShown: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface globalModalsLogicActions { + hideCreateOrganizationModal: () => { + value: true + } + hideCreateProjectModal: () => { + value: true + } + showCreateOrganizationModal: () => { + value: true + } + showCreateProjectModal: () => { + value: true + } +} + +export type globalModalsLogicType = MakeLogicType export const globalModalsLogic = kea([ path(['layout', 'navigation', 'globalModalsLogic']), diff --git a/frontend/src/layout/navigation-3000/navigationLogic.tsx b/frontend/src/layout/navigation-3000/navigationLogic.tsx index c068e7b30cc3..b566a445b7c7 100644 --- a/frontend/src/layout/navigation-3000/navigationLogic.tsx +++ b/frontend/src/layout/navigation-3000/navigationLogic.tsx @@ -1,4 +1,4 @@ -import { actions, connect, events, kea, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, events, kea, listeners, path, props, reducers, selectors } from 'kea' import { router } from 'kea-router' import { subscriptions } from 'kea-subscriptions' import posthog from 'posthog-js' @@ -48,8 +48,10 @@ import { dashboardsModel } from '~/models/dashboardsModel' import { groupsModel } from '~/models/groupsModel' import { AccessControlLevel, AccessControlResourceType, ReplayTabs } from '~/types' +import type { GroupsAccessStatus } from '../../lib/introductions/groupsAccessLogic' +import type { SceneConfig, SceneExport, SceneParams, SceneProps } from '../../scenes/sceneTypes' +import type { GroupType, GroupTypeIndex, SavedSessionRecordingPlaylistsResult } from '../../types' import { navigationLogic } from '../navigation/navigationLogic' -import type { navigation3000LogicType } from './navigationLogicType' import { BasicListItem, ExtendedListItem, NavbarItem, SidebarNavbarItem } from './types' /** Multi-segment item keys are joined using this separator for easy comparisons. */ @@ -64,6 +66,178 @@ const DEFAULT_SIDEBAR_WIDTH_PX: number = 288 const MAXIMUM_SIDEBAR_WIDTH_PX: number = 1024 const MAXIMUM_SIDEBAR_WIDTH_PERCENTAGE: number = 50 +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navigation3000LogicValues { + groupTypes: Map; // groupsModel + groupsAccessStatus: GroupsAccessStatus; // groupsModel + mobileLayout: boolean; // navigationLogic + isCurrentOrganizationUnavailable: boolean; // organizationLogic + activeSceneId: string | null; // sceneLogic + sceneConfig: SceneConfig | null; // sceneLogic + savedFilters: SavedSessionRecordingPlaylistsResult; // sessionRecordingSavedFiltersLogic + savedFiltersLoading: boolean; // sessionRecordingSavedFiltersLogic + accordionCollapseMapping: Record; + activeNavbarItem: SidebarNavbarItem | null; + activeNavbarItemId: string | null; + activeNavbarItemIdRaw: string; + internalSearchTerm: string; + isListItemVisible: (key: string) => boolean; + isNavCollapsed: boolean; + isNavCollapsedDesktop: boolean; + isNavShown: boolean; + isNavShownMobile: boolean; + isResizeInProgress: boolean; + isSearchShown: boolean; + isSidebarKeyboardShortcutAcknowledged: boolean; + isSidebarShown: boolean; + lastFocusedItemIndex: number; + listItemAccordionCollapseMapping: Record; + mode: Navigation3000Mode; + navbarItemIdMapping: Record; + navbarItems: NavbarItem[][]; + newItemCategory: string | null; + newItemInlineCategory: string | null; + normalizedActiveListItemKey: number | string | string[] | null; + savingNewItem: boolean; + searchTerm: string; + sidebarContentsFlattened: BasicListItem[] | ExtendedListItem[]; + sidebarOverslide: number; + sidebarOverslideDirection: "max" | "min" | null; + sidebarWidth: number; + zenMode: boolean; + zenModeFromUrl: boolean; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navigation3000LogicActions { + setScene: (sceneId: string, sceneKey: string | undefined, params: SceneParams, scrollToTop?: boolean | undefined, exportedScene?: SceneExport | undefined) => { + exportedScene: SceneExport | undefined; + params: SceneParams; + sceneId: string; + sceneKey: string | undefined; + scrollToTop: boolean; + }; // sceneLogic + acknowledgeSidebarKeyboardShortcut: () => { + value: true; + }; + beginResize: () => { + value: true; + }; + cancelNewItem: () => { + value: true; + }; + endResize: () => { + value: true; + }; + focusNextItem: () => { + value: true; + }; + focusPreviousItem: () => { + value: true; + }; + hideNavOnMobile: () => { + value: true; + }; + hideSidebar: () => { + value: true; + }; + initiateNewItemInCategory: (category: string) => { + category: string; + }; + initiateNewItemInlineInCategory: (category: string) => { + category: string; + }; + saveNewItem: (itemName: string) => { + itemName: string; + }; + saveNewItemComplete: () => { + value: true; + }; + setIsSearchShown: (isSearchShown: boolean) => { + isSearchShown: boolean; + }; + setLastFocusedItemByKey: (key: number | string) => { + key: number | string; + }; + setLastFocusedItemIndex: (index: number) => { + index: number; + }; + setSearchTerm: (searchTerm: string) => { + searchTerm: string; + }; + setSidebarOverslide: (overslide: number) => { + overslide: number; + }; + setSidebarWidth: (width: number) => { + width: number; + }; + setZenMode: (zenMode: boolean, trigger: ZenModeTrigger) => { + trigger: ZenModeTrigger; + zenMode: boolean; + }; + showNavOnMobile: () => { + value: true; + }; + showSidebar: (newNavbarItemId?: string) => { + newNavbarItemId: string | undefined; + }; + syncSidebarWidthWithMouseMove: (delta: number) => { + delta: number; + }; + syncSidebarWidthWithViewport: () => { + value: true; + }; + toggleAccordion: (key: string) => { + key: string; + }; + toggleListItemAccordion: (key: string) => { + key: string; + }; + toggleNavCollapsed: (override?: boolean) => { + override: boolean | undefined; + }; + toggleSidebar: () => { + value: true; + }; + toggleZenMode: (trigger: ZenModeTrigger) => { + trigger: ZenModeTrigger; + }; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navigation3000LogicProps { + inputElement?: HTMLInputElement | null; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navigation3000LogicMeta { + __keaTypeGenInternalSelectorTypes: { + zenModeFromUrl: (searchParams: Record) => boolean; + mode: (sceneConfig: SceneConfig | null, isCurrentOrganizationUnavailable: boolean, zenMode: boolean, activeSceneId: string | null, featureFlags: import("lib/logic/featureFlagLogic").FeatureFlagsSet) => Navigation3000Mode; + isNavShown: (isNavShownMobile: boolean, mobileLayout: boolean) => boolean; + isNavCollapsed: (isNavCollapsedDesktop: boolean, mobileLayout: boolean) => boolean; + navbarItems: (featureFlags: import("lib/logic/featureFlagLogic").FeatureFlagsSet, dashboardsLoading: boolean, pinnedDashboards: (import("~/types").DashboardBasicType | import("~/types").DashboardType>>>)[], savedFilters: SavedSessionRecordingPlaylistsResult, savedFiltersLoading: boolean) => NavbarItem[][]; + navbarItemIdMapping: (navbarItems: NavbarItem[][]) => Record; + sidebarOverslideDirection: (sidebarOverslide: number) => "max" | "min" | null; + activeNavbarItem: (activeNavbarItemId: string | null, navbarItemIdMapping: Record) => SidebarNavbarItem | null; + searchTerm: (internalSearchTerm: string, isSearchShown: boolean) => string; + sidebarContentsFlattened: (arg: import("./types").SidebarCategory[] | null) => BasicListItem[] | ExtendedListItem[]; + normalizedActiveListItemKey: (arg: number | string | [ + string, + number | string + ] | null) => number | string | string[] | null; + isListItemVisible: (listItemAccordionCollapseMapping: Record) => (key: string) => boolean; + activeNavbarItemId: (activeNavbarItemIdRaw: string) => string | null; + newItemCategory: (arg: import("./types").SidebarCategory[] | null, newItemInlineCategory: string | null, location: { + hash: string; + pathname: string; + search: string; + }) => string | null; + }; +} + +export type navigation3000LogicType = MakeLogicType; + export const navigation3000Logic = kea([ path(['layout', 'navigation-3000', 'navigationLogic']), props({} as { inputElement?: HTMLInputElement | null }), @@ -356,7 +530,7 @@ export const navigation3000Logic = kea([ selectors({ zenModeFromUrl: [ () => [router.selectors.searchParams], - (searchParams): boolean => { + (searchParams: Record): boolean => { // Enable zen mode via ?zen or ?zen=true or ?zen=1 const zenParam = searchParams?.zen return zenParam !== undefined && zenParam !== 'false' && zenParam !== '0' @@ -371,11 +545,11 @@ export const navigation3000Logic = kea([ featureFlagLogic.selectors.featureFlags, ], ( - sceneConfig, - isCurrentOrganizationUnavailable, - zenMode, - activeSceneId, - featureFlags + sceneConfig: null | import('scenes/sceneTypes').SceneConfig, + isCurrentOrganizationUnavailable: boolean, + zenMode: boolean, + activeSceneId: string | null, + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet ): Navigation3000Mode => { if (zenMode) { return 'zen' @@ -400,11 +574,11 @@ export const navigation3000Logic = kea([ ], isNavShown: [ (s) => [s.isNavShownMobile, s.mobileLayout], - (isNavShownMobile, mobileLayout): boolean => !mobileLayout || isNavShownMobile, + (isNavShownMobile: boolean, mobileLayout: boolean): boolean => !mobileLayout || isNavShownMobile, ], isNavCollapsed: [ (s) => [s.isNavCollapsedDesktop, s.mobileLayout], - (isNavCollapsedDesktop, mobileLayout): boolean => !mobileLayout && isNavCollapsedDesktop, + (isNavCollapsedDesktop: boolean, mobileLayout: boolean): boolean => !mobileLayout && isNavCollapsedDesktop, ], navbarItems: [ (s) => [ @@ -414,7 +588,20 @@ export const navigation3000Logic = kea([ s.savedFilters, s.savedFiltersLoading, ], - (featureFlags, dashboardsLoading, pinnedDashboards, savedFilters, savedFiltersLoading): NavbarItem[][] => { + ( + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + dashboardsLoading: boolean, + pinnedDashboards: ( + | import('~/types').DashboardBasicType + | import('~/types').DashboardType< + import('~/types').QueryBasedInsightModel< + import('../../queries/schema').Node> + > + > + )[], + savedFilters: import('~/types').SavedSessionRecordingPlaylistsResult, + savedFiltersLoading: boolean + ): NavbarItem[][] => { return [ [ { @@ -690,13 +877,13 @@ export const navigation3000Logic = kea([ ], navbarItemIdMapping: [ (s) => [s.navbarItems], - (navbarItems): Record => { + (navbarItems: NavbarItem[][]): Record => { return Object.fromEntries(navbarItems.flat().map((item) => [item.identifier, item])) }, ], sidebarOverslideDirection: [ (s) => [s.sidebarOverslide], - (sidebarOverslide): 'min' | 'max' | null => { + (sidebarOverslide: number): 'min' | 'max' | null => { if (sidebarOverslide < 0) { return 'min' } else if (sidebarOverslide > 0) { @@ -707,20 +894,23 @@ export const navigation3000Logic = kea([ ], activeNavbarItem: [ (s) => [s.activeNavbarItemId, s.navbarItemIdMapping], - (activeNavbarItemId, navbarItemIdMapping): SidebarNavbarItem | null => { + ( + activeNavbarItemId: string | null, + navbarItemIdMapping: Record + ): SidebarNavbarItem | null => { const item = activeNavbarItemId ? navbarItemIdMapping[activeNavbarItemId] : null return item && 'logic' in item ? (item as SidebarNavbarItem) : null }, ], searchTerm: [ (s) => [s.internalSearchTerm, s.isSearchShown], - (internalSearchTerm, isSearchShown): string => { + (internalSearchTerm: string, isSearchShown: boolean): string => { return isSearchShown ? internalSearchTerm : '' }, ], sidebarContentsFlattened: [ (s) => [(state) => s.activeNavbarItem(state)?.logic?.findMounted()?.selectors.contents(state) || null], - (sidebarContents): BasicListItem[] | ExtendedListItem[] => { + (sidebarContents: import('./types').SidebarCategory[] | null): BasicListItem[] | ExtendedListItem[] => { const flattenItems = (items: any[]): (BasicListItem | ExtendedListItem)[] => { return items.flatMap((item) => { if ('items' in item) { @@ -737,7 +927,9 @@ export const navigation3000Logic = kea([ (state) => s.activeNavbarItem(state)?.logic?.findMounted()?.selectors.activeListItemKey?.(state) || null, ], - (activeListItemKey): string | number | string[] | null => + ( + activeListItemKey: number | string | [string, number | string] | null + ): string | number | string[] | null => activeListItemKey ? Array.isArray(activeListItemKey) ? activeListItemKey.join(ITEM_KEY_PART_SEPARATOR) @@ -746,7 +938,7 @@ export const navigation3000Logic = kea([ ], isListItemVisible: [ (s) => [s.listItemAccordionCollapseMapping], - (listItemAccordionCollapseMapping) => { + (listItemAccordionCollapseMapping: Record) => { return (key: string): boolean => { // Split the key into parts to check each parent's visibility const parts = key.split(ITEM_KEY_PART_SEPARATOR) @@ -763,7 +955,7 @@ export const navigation3000Logic = kea([ ], activeNavbarItemId: [ (s) => [s.activeNavbarItemIdRaw], - (activeNavbarItemIdRaw): string | null => { + (activeNavbarItemIdRaw: string): string | null => { if (activeNavbarItemIdRaw === Scene.SQLEditor) { return Scene.SQLEditor } @@ -776,7 +968,15 @@ export const navigation3000Logic = kea([ s.newItemInlineCategory, router.selectors.location, ], - (sidebarContents, newItemInlineCategory, location): string | null => { + ( + sidebarContents: import('./types').SidebarCategory[] | null, + newItemInlineCategory: string | null, + location: { + hash: string + pathname: string + search: string + } + ): string | null => { if (!sidebarContents) { return null } diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/accessControlsLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/accessControlsLogic.ts index 85fbef163684..0fbb3072dadb 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/accessControlsLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/accessControlsLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { urlToAction } from 'kea-router' @@ -20,10 +20,12 @@ import { OrganizationMemberType, } from '~/types' +import type { FeatureFlagsSet } from '../../../../../../lib/logic/featureFlagLogic' +import type { AccessControlUIVersion } from '../../../../../../lib/utils/accessControlUtils' +import type { AccessControlResponseType, AccessControlUpdateType, RoleType } from '../../../../../../types' import { accessControlLogic } from '../accessControlLogic' import { isResourceRolledOut, resourcesAccessControlLogic } from '../resourcesAccessControlLogic' import { roleAccessControlLogic } from '../roleAccessControlLogic' -import type { accessControlsLogicType } from './accessControlsLogicType' import { AccessControlFilters, AccessControlMemberEntry, @@ -84,6 +86,304 @@ function matchesFilters( return true } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface accessControlsLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + sortedMembers: OrganizationMemberType[] | null // membersLogic + resources: APIScopeObject[] // resourcesAccessControlLogic + roles: RoleType[] // roleAccessControlLogic + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean // userLogic + activeTab: AccessControlsTab + allMembers: OrganizationMemberType[] + availableProjectLevels: AccessControlLevel[] + availableResourceLevels: AccessControlLevel[] + canEdit: boolean + canUseRoles: boolean + defaults: AccessControlDefaultsResponse | null + defaultsLoading: boolean + filteredMembers: AccessControlMemberEntry[] + filteredRoles: AccessControlRoleEntry[] + filters: AccessControlFilters + loading: boolean + membersData: AccessControlMembersResponse | null + membersDataLoading: boolean + resourceKeys: { + key: APIScopeObject + label: string + }[] + resourcesWithProject: { + key: APIScopeObject + label: string + }[] + rolesData: AccessControlRolesResponse | null + rolesDataLoading: boolean + ruleModalState: GroupedAccessControlRuleModalLogicProps | null + ruleOptions: { + key: AccessControlLevel + label: string + }[] + searchText: string + visibleResourceKeySet: Set +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface accessControlsLogicActions { + updateAccessControlDefault: ( + level: AccessControlLevel, + source?: AccessControlUIVersion | undefined + ) => { + level: AccessControlLevel + source: AccessControlUIVersion + } // accessControlLogic + updateAccessControlDefaultSuccess: ( + accessControls: AccessControlResponseType | null, + payload?: + | { + level: AccessControlLevel + source: AccessControlUIVersion + } + | undefined + ) => { + accessControls: AccessControlResponseType | null + payload?: { + level: AccessControlLevel + source: AccessControlUIVersion + } + } // accessControlLogic + updateAccessControlMembers: ( + accessControls: { + level: AccessControlLevel | null + member: OrganizationMemberType['id'] + }[], + source?: AccessControlUIVersion | undefined + ) => { + accessControls: { + level: AccessControlLevel | null + member: string + }[] + source: AccessControlUIVersion + } // accessControlLogic + updateAccessControlMembersSuccess: ( + accessControls: AccessControlResponseType | null, + payload?: + | { + accessControls: { + level: AccessControlLevel | null + member: string + }[] + source: AccessControlUIVersion + } + | undefined + ) => { + accessControls: AccessControlResponseType | null + payload?: { + accessControls: { + level: AccessControlLevel | null + member: string + }[] + source: AccessControlUIVersion + } + } // accessControlLogic + updateAccessControlRoles: ( + accessControls: { + level: AccessControlLevel | null + role: RoleType['id'] + }[], + source?: AccessControlUIVersion | undefined + ) => { + accessControls: { + level: AccessControlLevel | null + role: string + }[] + source: AccessControlUIVersion + } // accessControlLogic + updateAccessControlRolesSuccess: ( + accessControls: AccessControlResponseType | null, + payload?: + | { + accessControls: { + level: AccessControlLevel | null + role: string + }[] + source: AccessControlUIVersion + } + | undefined + ) => { + accessControls: AccessControlResponseType | null + payload?: { + accessControls: { + level: AccessControlLevel | null + role: string + }[] + source: AccessControlUIVersion + } + } // accessControlLogic + updateResourceAccessControls: ( + accessControls: Pick[], + saveType: 'default' | 'member' | 'role' + ) => { + accessControls: Pick[] + saveType: 'default' | 'member' | 'role' + } // resourcesAccessControlLogic + updateResourceAccessControlsSuccess: ( + resourceAccessControls: AccessControlResponseType | null, + payload?: + | { + accessControls: Pick< + AccessControlUpdateType, + 'access_level' | 'organization_member' | 'resource' | 'role' + >[] + saveType: 'default' | 'member' | 'role' + } + | undefined + ) => { + payload?: { + accessControls: Pick< + AccessControlUpdateType, + 'access_level' | 'organization_member' | 'resource' | 'role' + >[] + saveType: 'default' | 'member' | 'role' + } + resourceAccessControls: AccessControlResponseType | null + } // resourcesAccessControlLogic + closeRuleModal: () => { + value: true + } + loadDefaults: () => any + loadDefaultsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadDefaultsSuccess: ( + defaults: AccessControlDefaultsResponse, + payload?: any + ) => { + defaults: AccessControlDefaultsResponse + payload?: any + } + loadMembers: () => any + loadMembersFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadMembersSuccess: ( + membersData: AccessControlMembersResponse, + payload?: any + ) => { + membersData: AccessControlMembersResponse + payload?: any + } + loadRoles: () => any + loadRolesFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadRolesSuccess: ( + rolesData: AccessControlRolesResponse, + payload?: any + ) => { + rolesData: AccessControlRolesResponse + payload?: any + } + openRuleModal: (state: GroupedAccessControlRuleModalLogicProps) => { + state: GroupedAccessControlRuleModalLogicProps + } + saveGroupedRules: (params: { + projectLevel: AccessControlLevel | null + resourceLevels: Record + scopeId: string + scopeType: ScopeType + }) => { + projectLevel: AccessControlLevel | null + resourceLevels: Record + scopeId: string + scopeType: ScopeType + } + setActiveTab: (activeTab: AccessControlsTab) => { + activeTab: AccessControlsTab + } + setFilters: (filters: Partial) => { + filters: Partial + } + setSearchText: (searchText: string) => { + searchText: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface accessControlsLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + allMembers: (sortedMembers: OrganizationMemberType[] | null) => OrganizationMemberType[] + canUseRoles: ( + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean + ) => boolean + canEdit: (defaults: AccessControlDefaultsResponse | null) => boolean + availableProjectLevels: (defaults: AccessControlDefaultsResponse | null) => AccessControlLevel[] + availableResourceLevels: (defaults: AccessControlDefaultsResponse | null) => AccessControlLevel[] + resourceKeys: ( + defaults: AccessControlDefaultsResponse | null, + resources: APIScopeObject[], + featureFlags: FeatureFlagsSet + ) => { + key: APIScopeObject + label: string + }[] + resourcesWithProject: ( + resourceKeys: { + key: APIScopeObject + label: string + }[] + ) => { + key: APIScopeObject + label: string + }[] + visibleResourceKeySet: ( + resourceKeys: { + key: APIScopeObject + label: string + }[] + ) => Set + ruleOptions: ( + availableProjectLevels: AccessControlLevel[], + availableResourceLevels: AccessControlLevel[] + ) => { + key: AccessControlLevel + label: string + }[] + filteredRoles: ( + rolesData: AccessControlRolesResponse | null, + searchText: string, + filters: AccessControlFilters, + canUseRoles: boolean, + visibleResourceKeySet: Set + ) => AccessControlRoleEntry[] + filteredMembers: ( + membersData: AccessControlMembersResponse | null, + searchText: string, + filters: AccessControlFilters, + visibleResourceKeySet: Set + ) => AccessControlMemberEntry[] + loading: (defaultsLoading: boolean, rolesDataLoading: boolean, membersDataLoading: boolean) => boolean + } +} + +export type accessControlsLogicType = MakeLogicType< + accessControlsLogicValues, + accessControlsLogicActions, + AccessControlsLogicProps, + accessControlsLogicMeta +> + export const accessControlsLogic = kea([ path([ 'layout', @@ -199,28 +499,41 @@ export const accessControlsLogic = kea([ }), selectors({ - allMembers: [(s) => [s.sortedMembers], (sortedMembers): OrganizationMemberType[] => sortedMembers ?? []], + allMembers: [ + (s) => [s.sortedMembers], + (sortedMembers: OrganizationMemberType[] | null): OrganizationMemberType[] => sortedMembers ?? [], + ], canUseRoles: [ (s) => [s.hasAvailableFeature], - (hasAvailableFeature): boolean => hasAvailableFeature(AvailableFeature.ROLE_BASED_ACCESS), + (hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean): boolean => + hasAvailableFeature(AvailableFeature.ROLE_BASED_ACCESS), ], - canEdit: [(s) => [s.defaults], (defaults): boolean => defaults?.can_edit ?? false], + canEdit: [ + (s) => [s.defaults], + (defaults: AccessControlDefaultsResponse | null): boolean => defaults?.can_edit ?? false, + ], availableProjectLevels: [ (s) => [s.defaults], - (defaults): AccessControlLevel[] => defaults?.available_project_levels ?? [], + (defaults: AccessControlDefaultsResponse | null): AccessControlLevel[] => + defaults?.available_project_levels ?? [], ], availableResourceLevels: [ (s) => [s.defaults], - (defaults): AccessControlLevel[] => defaults?.available_resource_levels ?? [], + (defaults: AccessControlDefaultsResponse | null): AccessControlLevel[] => + defaults?.available_resource_levels ?? [], ], resourceKeys: [ (s) => [s.defaults, s.resources, s.featureFlags], - (defaults, resources, featureFlags): { key: APIScopeObject; label: string }[] => { + ( + defaults: AccessControlDefaultsResponse | null, + resources: APIScopeObject[], + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet + ): { key: APIScopeObject; label: string }[] => { if (defaults) { return Object.keys(defaults.resource_access_levels) .filter((resource) => isResourceRolledOut(resource as AccessControlResourceType, featureFlags)) @@ -239,19 +552,32 @@ export const accessControlsLogic = kea([ resourcesWithProject: [ (s) => [s.resourceKeys], - (resourceKeys): { key: APIScopeObject; label: string }[] => { + ( + resourceKeys: { + key: APIScopeObject + label: string + }[] + ): { key: APIScopeObject; label: string }[] => { return [{ key: 'project' as APIScopeObject, label: 'Project' }, ...resourceKeys] }, ], visibleResourceKeySet: [ (s) => [s.resourceKeys], - (resourceKeys): Set => new Set(resourceKeys.map((r) => r.key)), + ( + resourceKeys: { + key: APIScopeObject + label: string + }[] + ): Set => new Set(resourceKeys.map((r) => r.key)), ], ruleOptions: [ (s) => [s.availableProjectLevels, s.availableResourceLevels], - (projectLevels, resourceLevels): { key: AccessControlLevel; label: string }[] => { + ( + projectLevels: AccessControlLevel[], + resourceLevels: AccessControlLevel[] + ): { key: AccessControlLevel; label: string }[] => { const levelSet = new Set() for (const level of projectLevels) { levelSet.add(level) @@ -271,7 +597,13 @@ export const accessControlsLogic = kea([ filteredRoles: [ (s) => [s.rolesData, s.searchText, s.filters, s.canUseRoles, s.visibleResourceKeySet], - (rolesData, searchText, filters, canUseRoles, visibleResourceKeySet): AccessControlRoleEntry[] => { + ( + rolesData: AccessControlRolesResponse | null, + searchText: string, + filters: AccessControlFilters, + canUseRoles: boolean, + visibleResourceKeySet: Set + ): AccessControlRoleEntry[] => { if (!canUseRoles || !rolesData) { return [] } @@ -290,7 +622,12 @@ export const accessControlsLogic = kea([ filteredMembers: [ (s) => [s.membersData, s.searchText, s.filters, s.visibleResourceKeySet], - (membersData, searchText, filters, visibleResourceKeySet): AccessControlMemberEntry[] => { + ( + membersData: AccessControlMembersResponse | null, + searchText: string, + filters: AccessControlFilters, + visibleResourceKeySet: Set + ): AccessControlMemberEntry[] => { if (!membersData) { return [] } @@ -317,7 +654,7 @@ export const accessControlsLogic = kea([ loading: [ (s) => [s.defaultsLoading, s.rolesDataLoading, s.membersDataLoading], - (defaultsLoading, rolesLoading, membersLoading): boolean => + (defaultsLoading: boolean, rolesLoading: boolean, membersLoading: boolean): boolean => defaultsLoading || rolesLoading || membersLoading, ], }), diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/groupedAccessControlRuleModalLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/groupedAccessControlRuleModalLogic.ts index 2704f0c65da0..fc982f2fdd12 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/groupedAccessControlRuleModalLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/ResourceAccessControlsV2/groupedAccessControlRuleModalLogic.ts @@ -1,11 +1,172 @@ -import { actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { APIScopeObject, AccessControlLevel, EffectiveAccessControlEntry } from '~/types' import { accessControlsLogic } from './accessControlsLogic' -import type { groupedAccessControlRuleModalLogicType } from './groupedAccessControlRuleModalLogicType' import { getEntryId, getInheritedReasonTooltip, getLevelOptionsForResource } from './helpers' import { FormAccessLevel, GroupedAccessControlRuleModalLogicProps } from './types' +import type { AccessControlSettingsEntry, ScopeType } from './types' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupedAccessControlRuleModalLogicValues { + availableProjectLevels: AccessControlLevel[] // accessControlsLogic + availableResourceLevels: AccessControlLevel[] // accessControlsLogic + canEdit: boolean // accessControlsLogic + loading: boolean // accessControlsLogic + entry: AccessControlSettingsEntry + entryId: string + featuresDisabledReason: + | 'Cannot edit' + | 'Loading...' + | 'User is an organization admin and has access to all features' + | undefined + formProjectLevel: FormAccessLevel + formResourceLevels: Record + isOrgAdmin: boolean + isProjectLevelShowingInherited: boolean + isResourceLevelShowingInherited: (resource: APIScopeObject) => boolean + modalTitle: 'Update default access' | 'Update member access' | 'Update role access' + projectDisabledReason: 'Cannot edit' | 'Loading...' | 'User is an organization admin' | undefined + projectInheritedReasonTooltip: string | undefined + projectLevelOptions: { + disabledReason?: string | undefined + label: string + value: AccessControlLevel + }[] + resourceInheritedReasonTooltip: (resource: APIScopeObject) => string | undefined + resourceLevelOptions: ( + resource: APIScopeObject, + resourceLabel: string + ) => ( + | { + disabledReason?: string | undefined + label: string + value: AccessControlLevel + } + | { + disabledReason: undefined + label: string + value: AccessControlLevel | null + } + )[] + scopeType: ScopeType + showResourceAddOverrideButton: (resource: APIScopeObject) => boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupedAccessControlRuleModalLogicActions { + closeRuleModal: () => { + value: true + } // accessControlsLogic + saveGroupedRules: (params: { + projectLevel: AccessControlLevel | null + resourceLevels: Record + scopeId: string + scopeType: ScopeType + }) => { + projectLevel: AccessControlLevel | null + resourceLevels: Record + scopeId: string + scopeType: ScopeType + } // accessControlsLogic + clearResourceOverrides: () => { + value: true + } + close: () => { + value: true + } + save: () => { + value: true + } + setProjectLevel: (level: AccessControlLevel | null) => { + level: AccessControlLevel | null + } + setResourceLevel: ( + resource: APIScopeObject, + level: AccessControlLevel | null + ) => { + level: AccessControlLevel | null + resource: APIScopeObject + } + setResourceLevels: (levels: Record) => { + levels: Record + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupedAccessControlRuleModalLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + entry: (entry: AccessControlSettingsEntry) => AccessControlSettingsEntry + scopeType: (scopeType: ScopeType) => ScopeType + entryId: (entry: AccessControlSettingsEntry) => string + modalTitle: (scopeType: ScopeType) => 'Update default access' | 'Update member access' | 'Update role access' + isOrgAdmin: (entry: AccessControlSettingsEntry) => boolean + featuresDisabledReason: ( + loading: boolean, + canEdit: boolean, + isOrgAdmin: boolean + ) => 'Cannot edit' | 'Loading...' | 'User is an organization admin and has access to all features' | undefined + isProjectLevelShowingInherited: ( + formProjectLevel: FormAccessLevel, + entry: AccessControlSettingsEntry + ) => boolean + projectInheritedReasonTooltip: ( + isProjectLevelShowingInherited: boolean, + entry: AccessControlSettingsEntry + ) => string | undefined + projectLevelOptions: ( + availableProjectLevels: AccessControlLevel[], + entry: AccessControlSettingsEntry + ) => { + disabledReason?: string | undefined + label: string + value: AccessControlLevel + }[] + projectDisabledReason: ( + loading: boolean, + canEdit: boolean, + isOrgAdmin: boolean + ) => 'Cannot edit' | 'Loading...' | 'User is an organization admin' | undefined + isResourceLevelShowingInherited: ( + formResourceLevels: Record, + entry: AccessControlSettingsEntry + ) => (resource: APIScopeObject) => boolean + resourceInheritedReasonTooltip: ( + isResourceLevelShowingInherited: (resource: APIScopeObject) => boolean, + entry: AccessControlSettingsEntry + ) => (resource: APIScopeObject) => string | undefined + resourceLevelOptions: ( + availableResourceLevels: AccessControlLevel[], + entry: AccessControlSettingsEntry, + formResourceLevels: Record + ) => ( + resource: APIScopeObject, + resourceLabel: string + ) => ( + | { + disabledReason?: string | undefined + label: string + value: AccessControlLevel + } + | { + disabledReason: undefined + label: string + value: AccessControlLevel | null + } + )[] + showResourceAddOverrideButton: ( + formResourceLevels: Record + ) => (resource: APIScopeObject) => boolean + } +} + +export type groupedAccessControlRuleModalLogicType = MakeLogicType< + groupedAccessControlRuleModalLogicValues, + groupedAccessControlRuleModalLogicActions, + GroupedAccessControlRuleModalLogicProps, + groupedAccessControlRuleModalLogicMeta +> export const groupedAccessControlRuleModalLogic = kea([ path((key) => ['scenes', 'access_control', 'groupedAccessControlRuleModalLogic', key]), @@ -51,13 +212,13 @@ export const groupedAccessControlRuleModalLogic = kea [p.entry], (entry) => entry], - scopeType: [(_, p) => [p.scopeType], (scopeType) => scopeType], - entryId: [(_, p) => [p.entry], (entry) => getEntryId(entry)], + entry: [(_, p) => [p.entry], (entry: import('./types').AccessControlSettingsEntry) => entry], + scopeType: [(_, p) => [p.scopeType], (scopeType: import('./types').ScopeType) => scopeType], + entryId: [(_, p) => [p.entry], (entry: import('./types').AccessControlSettingsEntry) => getEntryId(entry)], modalTitle: [ (s) => [s.scopeType], - (scopeType) => { + (scopeType: import('./types').ScopeType) => { switch (scopeType) { case 'default': return 'Update default access' @@ -68,10 +229,14 @@ export const groupedAccessControlRuleModalLogic = kea [s.entry], (entry) => entry.project.inherited_access_level_reason === 'organization_admin'], + isOrgAdmin: [ + (s) => [s.entry], + (entry: import('./types').AccessControlSettingsEntry) => + entry.project.inherited_access_level_reason === 'organization_admin', + ], featuresDisabledReason: [ (s) => [s.loading, s.canEdit, s.isOrgAdmin], - (loading, canEdit, isOrgAdmin) => { + (loading: boolean, canEdit: boolean, isOrgAdmin: boolean) => { if (loading) { return 'Loading...' } @@ -88,20 +253,20 @@ export const groupedAccessControlRuleModalLogic = kea [s.formProjectLevel, s.entry], - (formProjectLevel, entry) => + (formProjectLevel: FormAccessLevel, entry: import('./types').AccessControlSettingsEntry) => formProjectLevel === entry.project.inherited_access_level && entry.project.inherited_access_level !== null, ], projectInheritedReasonTooltip: [ (s) => [s.isProjectLevelShowingInherited, s.entry], - (isProjectLevelShowingInherited, entry) => + (isProjectLevelShowingInherited: boolean, entry: import('./types').AccessControlSettingsEntry) => isProjectLevelShowingInherited ? getInheritedReasonTooltip(entry.project.inherited_access_level_reason) : undefined, ], projectLevelOptions: [ (s) => [s.availableProjectLevels, s.entry], - (availableProjectLevels, entry) => { + (availableProjectLevels: AccessControlLevel[], entry: import('./types').AccessControlSettingsEntry) => { const { inherited_access_level, inherited_access_level_reason, minimum, maximum } = entry.project return getLevelOptionsForResource(availableProjectLevels, { minimum, @@ -114,7 +279,7 @@ export const groupedAccessControlRuleModalLogic = kea [s.loading, s.canEdit, s.isOrgAdmin], - (loading, canEdit, isOrgAdmin) => { + (loading: boolean, canEdit: boolean, isOrgAdmin: boolean) => { if (loading) { return 'Loading...' } @@ -131,26 +296,38 @@ export const groupedAccessControlRuleModalLogic = kea [s.formResourceLevels, s.entry], - (formResourceLevels, entry) => (resource: APIScopeObject) => { - const resourceEntry = entry.resources[resource] as EffectiveAccessControlEntry - return ( - formResourceLevels[resource] === resourceEntry.inherited_access_level && - resourceEntry.inherited_access_level !== null - ) - }, + ( + formResourceLevels: Record, + entry: import('./types').AccessControlSettingsEntry + ) => + (resource: APIScopeObject) => { + const resourceEntry = entry.resources[resource] as EffectiveAccessControlEntry + return ( + formResourceLevels[resource] === resourceEntry.inherited_access_level && + resourceEntry.inherited_access_level !== null + ) + }, ], resourceInheritedReasonTooltip: [ (s) => [s.isResourceLevelShowingInherited, s.entry], - (isResourceLevelShowingInherited, entry) => (resource: APIScopeObject) => - isResourceLevelShowingInherited(resource) - ? getInheritedReasonTooltip( - (entry.resources[resource] as EffectiveAccessControlEntry).inherited_access_level_reason - ) - : undefined, + ( + isResourceLevelShowingInherited: (resource: APIScopeObject) => boolean, + entry: import('./types').AccessControlSettingsEntry + ) => + (resource: APIScopeObject) => + isResourceLevelShowingInherited(resource) + ? getInheritedReasonTooltip( + (entry.resources[resource] as EffectiveAccessControlEntry).inherited_access_level_reason + ) + : undefined, ], resourceLevelOptions: [ (s) => [s.availableResourceLevels, s.entry, s.formResourceLevels], - (availableResourceLevels, entry, formResourceLevels) => + ( + availableResourceLevels: AccessControlLevel[], + entry: import('./types').AccessControlSettingsEntry, + formResourceLevels: Record + ) => (resource: APIScopeObject, resourceLabel: string) => { const { access_level, inherited_access_level, inherited_access_level_reason, minimum, maximum } = entry.resources[resource] as EffectiveAccessControlEntry @@ -179,7 +356,8 @@ export const groupedAccessControlRuleModalLogic = kea [s.formResourceLevels], - (formResourceLevels) => (resource: APIScopeObject) => formResourceLevels[resource] === null, + (formResourceLevels: Record) => (resource: APIScopeObject) => + formResourceLevels[resource] === null, ], }), diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/accessControlLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/accessControlLogic.ts index 161194d85e10..98873b3db56c 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/accessControlLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/accessControlLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, selectors } from 'kea' import { loaders } from 'kea-loaders' import { LemonSelectOption } from '@posthog/lemon-ui' @@ -25,7 +25,7 @@ import { RoleType, } from '~/types' -import type { accessControlLogicType } from './accessControlLogicType' +import type { GuardAvailableFeatureFn } from '../../../../../lib/components/UpgradeModal/upgradeModalLogic' import { roleAccessControlLogic } from './roleAccessControlLogic' export type AccessControlLogicProps = { @@ -35,6 +35,212 @@ export type AccessControlLogicProps = { description: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface accessControlLogicValues { + sortedMembers: OrganizationMemberType[] | null // membersLogic + roles: RoleType[] // roleAccessControlLogic + currentProjectId: number | string // teamLogic + guardAvailableFeature: GuardAvailableFeatureFn // upgradeModalLogic + accessControlDefault: AccessControlTypeProject + accessControlDefaultLevel: string | null + accessControlDefaultOptions: LemonSelectOption[] + accessControlMembers: (AccessControlTypeMember | AccessControlTypeOrganizationAdmins)[] + accessControlRoles: AccessControlTypeRole[] + accessControls: AccessControlResponseType | null + accessControlsLoading: boolean + addableMembers: any[] + addableRoles: RoleType[] + availableLevels: AccessControlLevel[] + availableLevelsWithNone: AccessControlLevel[] + canEditAccessControls: boolean | null + endpoint: string + humanReadableResource: string + membersById: Record + minimumAccessLevel: AccessControlLevel | null + organizationAdmins: OrganizationMemberType[] + organizationAdminsAsAccessControlMember: AccessControlTypeOrganizationAdmins + resource: APIScopeObject + rolesById: Record +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface accessControlLogicActions { + ensureAllMembersLoaded: () => { + value: true + } // membersLogic + loadAccessControls: () => any + loadAccessControlsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadAccessControlsSuccess: ( + accessControls: AccessControlResponseType, + payload?: any + ) => { + accessControls: AccessControlResponseType + payload?: any + } + updateAccessControl: (accessControl: Pick) => { + accessControl: Pick + } + updateAccessControlDefault: ( + level: AccessControlLevel, + source?: AccessControlUIVersion + ) => { + level: AccessControlLevel + source: AccessControlUIVersion + } + updateAccessControlDefaultFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + updateAccessControlDefaultSuccess: ( + accessControls: AccessControlResponseType | null, + payload?: { + level: AccessControlLevel + source: AccessControlUIVersion + } + ) => { + accessControls: AccessControlResponseType | null + payload?: { + level: AccessControlLevel + source: AccessControlUIVersion + } + } + updateAccessControlMembers: ( + accessControls: { + level: AccessControlLevel | null + member: OrganizationMemberType['id'] + }[], + source?: AccessControlUIVersion + ) => { + accessControls: { + level: AccessControlLevel | null + member: string + }[] + source: AccessControlUIVersion + } + updateAccessControlMembersFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + updateAccessControlMembersSuccess: ( + accessControls: AccessControlResponseType | null, + payload?: { + accessControls: { + level: AccessControlLevel | null + member: string + }[] + source: AccessControlUIVersion + } + ) => { + accessControls: AccessControlResponseType | null + payload?: { + accessControls: { + level: AccessControlLevel | null + member: string + }[] + source: AccessControlUIVersion + } + } + updateAccessControlRoles: ( + accessControls: { + level: AccessControlLevel | null + role: RoleType['id'] + }[], + source?: AccessControlUIVersion + ) => { + accessControls: { + level: AccessControlLevel | null + role: string + }[] + source: AccessControlUIVersion + } + updateAccessControlRolesFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + updateAccessControlRolesSuccess: ( + accessControls: AccessControlResponseType | null, + payload?: { + accessControls: { + level: AccessControlLevel | null + role: string + }[] + source: AccessControlUIVersion + } + ) => { + accessControls: AccessControlResponseType | null + payload?: { + accessControls: { + level: AccessControlLevel | null + role: string + }[] + source: AccessControlUIVersion + } + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface accessControlLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + resource: (resource: APIScopeObject) => APIScopeObject + endpoint: (currentProjectId: number | string, resource: APIScopeObject, resource_id: string) => string + humanReadableResource: (resource: APIScopeObject) => string + minimumAccessLevel: (accessControls: AccessControlResponseType | null) => AccessControlLevel | null + availableLevelsWithNone: (accessControls: AccessControlResponseType | null) => AccessControlLevel[] + availableLevels: (availableLevelsWithNone: AccessControlLevel[]) => AccessControlLevel[] + canEditAccessControls: (accessControls: AccessControlResponseType | null) => boolean | null + accessControlDefaultLevel: (accessControls: AccessControlResponseType | null) => string | null + accessControlDefaultOptions: ( + availableLevelsWithNone: AccessControlLevel[], + minimumAccessLevel: AccessControlLevel | null, + arg: any + ) => LemonSelectOption[] + accessControlDefault: ( + accessControls: AccessControlResponseType | null, + accessControlDefaultLevel: string | null + ) => AccessControlTypeProject + organizationAdmins: (sortedMembers: OrganizationMemberType[] | null) => OrganizationMemberType[] + organizationAdminsAsAccessControlMember: ( + organizationAdmins: OrganizationMemberType[] + ) => AccessControlTypeOrganizationAdmins + accessControlMembers: ( + accessControls: AccessControlResponseType | null, + organizationAdminsAsAccessControlMember: AccessControlTypeOrganizationAdmins + ) => (AccessControlTypeMember | AccessControlTypeOrganizationAdmins)[] + accessControlRoles: (accessControls: AccessControlResponseType | null) => AccessControlTypeRole[] + rolesById: (roles: RoleType[]) => Record + addableRoles: (roles: RoleType[], accessControlRoles: AccessControlTypeRole[]) => RoleType[] + membersById: (sortedMembers: OrganizationMemberType[] | null) => Record + addableMembers: ( + sortedMembers: OrganizationMemberType[] | null, + accessControlMembers: (AccessControlTypeMember | AccessControlTypeOrganizationAdmins)[], + organizationAdmins: OrganizationMemberType[] + ) => any[] + } +} + +export type accessControlLogicType = MakeLogicType< + accessControlLogicValues, + accessControlLogicActions, + AccessControlLogicProps, + accessControlLogicMeta +> + export const accessControlLogic = kea([ props({} as AccessControlLogicProps), key((props) => `${props.resource}-${props.resource_id}`), @@ -167,11 +373,11 @@ export const accessControlLogic = kea([ updateAccessControlMembersSuccess: () => actions.loadAccessControls(), })), selectors({ - resource: [(_, p) => [p.resource], (resource) => resource], + resource: [(_, p) => [p.resource], (resource: APIScopeObject) => resource], endpoint: [ (s, p) => [s.currentProjectId, p.resource, p.resource_id], - (currentProjectId, resource, resource_id): string => { + (currentProjectId: number | string, resource: APIScopeObject, resource_id: string): string => { // TODO: This is far from perfect... but it's a start if (resource === 'project') { return `api/projects/${currentProjectId}/access_controls` @@ -186,46 +392,49 @@ export const accessControlLogic = kea([ }, ], - humanReadableResource: [(_, p) => [p.resource], (resource) => resource.replace(/_/g, ' ')], + humanReadableResource: [(_, p) => [p.resource], (resource: APIScopeObject) => resource.replace(/_/g, ' ')], minimumAccessLevel: [ (s) => [s.accessControls], - (accessControls): AccessControlLevel | null => { + (accessControls: AccessControlResponseType | null): AccessControlLevel | null => { return accessControls?.minimum_access_level ?? null }, ], availableLevelsWithNone: [ (s) => [s.accessControls], - (accessControls): AccessControlLevel[] => { + (accessControls: AccessControlResponseType | null): AccessControlLevel[] => { return accessControls?.available_access_levels ?? [] }, ], availableLevels: [ (s) => [s.availableLevelsWithNone], - (availableLevelsWithNone): AccessControlLevel[] => { + (availableLevelsWithNone: AccessControlLevel[]): AccessControlLevel[] => { return availableLevelsWithNone.filter((level) => level !== 'none') }, ], canEditAccessControls: [ (s) => [s.accessControls], - (accessControls): boolean | null => { + (accessControls: AccessControlResponseType | null): boolean | null => { return accessControls?.user_can_edit_access_levels ?? null }, ], accessControlDefaultLevel: [ (s) => [s.accessControls], - (accessControls): string | null => { + (accessControls: AccessControlResponseType | null): string | null => { return accessControls?.default_access_level ?? null }, ], accessControlDefaultOptions: [ (s) => [s.availableLevelsWithNone, s.minimumAccessLevel, (_, props) => props.resource], - (availableLevelsWithNone, minimumAccessLevel): LemonSelectOption[] => { + ( + availableLevelsWithNone: AccessControlLevel[], + minimumAccessLevel: AccessControlLevel | null + ): LemonSelectOption[] => { const options = availableLevelsWithNone.map((level) => { const isDisabled = minimumAccessLevel ? availableLevelsWithNone.indexOf(level) < availableLevelsWithNone.indexOf(minimumAccessLevel) @@ -244,7 +453,10 @@ export const accessControlLogic = kea([ accessControlDefault: [ (s) => [s.accessControls, s.accessControlDefaultLevel], - (accessControls, accessControlDefaultLevel): AccessControlTypeProject => { + ( + accessControls: AccessControlResponseType | null, + accessControlDefaultLevel: string | null + ): AccessControlTypeProject => { const found = accessControls?.access_controls?.find( (accessControl) => !accessControl.organization_member && !accessControl.role ) as AccessControlTypeProject @@ -258,14 +470,14 @@ export const accessControlLogic = kea([ organizationAdmins: [ (s) => [s.sortedMembers], - (members): OrganizationMemberType[] => { + (members: OrganizationMemberType[] | null): OrganizationMemberType[] => { return members?.filter((member) => member.level >= OrganizationMembershipLevel.Admin) ?? [] }, ], organizationAdminsAsAccessControlMember: [ (s) => [s.organizationAdmins], - (organizationAdmins): AccessControlTypeOrganizationAdmins => { + (organizationAdmins: OrganizationMemberType[]): AccessControlTypeOrganizationAdmins => { return { organization_admin_members: organizationAdmins.map((member) => member.id), access_level: AccessControlLevel.Admin, @@ -280,8 +492,8 @@ export const accessControlLogic = kea([ accessControlMembers: [ (s) => [s.accessControls, s.organizationAdminsAsAccessControlMember], ( - accessControls, - organizationAdminsAsAccessControlMember + accessControls: AccessControlResponseType | null, + organizationAdminsAsAccessControlMember: AccessControlTypeOrganizationAdmins ): (AccessControlTypeMember | AccessControlTypeOrganizationAdmins)[] => { const members = (accessControls?.access_controls || []) .filter((accessControl) => !!accessControl.organization_member) @@ -297,7 +509,7 @@ export const accessControlLogic = kea([ accessControlRoles: [ (s) => [s.accessControls], - (accessControls): AccessControlTypeRole[] => { + (accessControls: AccessControlResponseType | null): AccessControlTypeRole[] => { return (accessControls?.access_controls || []).filter( (accessControl) => !!accessControl.role ) as AccessControlTypeRole[] @@ -306,28 +518,32 @@ export const accessControlLogic = kea([ rolesById: [ (s) => [s.roles], - (roles): Record => { + (roles: RoleType[]): Record => { return Object.fromEntries((roles || []).map((role) => [role.id, role])) }, ], addableRoles: [ (s) => [s.roles, s.accessControlRoles], - (roles, accessControlRoles): RoleType[] => { + (roles: RoleType[], accessControlRoles: AccessControlTypeRole[]): RoleType[] => { return roles ? roles.filter((role) => !accessControlRoles.find((ac) => ac.role === role.id)) : [] }, ], membersById: [ (s) => [s.sortedMembers], - (members): Record => { + (members: OrganizationMemberType[] | null): Record => { return Object.fromEntries((members || []).map((member) => [member.id, member])) }, ], addableMembers: [ (s) => [s.sortedMembers, s.accessControlMembers, s.organizationAdmins], - (members, accessControlMembers, organizationAdmins): any[] => { + ( + members: OrganizationMemberType[] | null, + accessControlMembers: (AccessControlTypeMember | AccessControlTypeOrganizationAdmins)[], + organizationAdmins: OrganizationMemberType[] + ): any[] => { return members ? members.filter( (member) => diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/resourcesAccessControlLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/resourcesAccessControlLogic.ts index 28d032475f49..82b70aeffbd6 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/resourcesAccessControlLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/resourcesAccessControlLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { lemonToast } from '@posthog/lemon-ui' @@ -24,7 +24,7 @@ import { RoleType, } from '~/types' -import type { resourcesAccessControlLogicType } from './resourcesAccessControlLogicType' +import type { FeatureFlagsSet } from '../../../../../lib/logic/featureFlagLogic' import { roleAccessControlLogic } from './roleAccessControlLogic' export type DefaultResourceAccessControls = { @@ -58,6 +58,140 @@ export function isResourceRolledOut( return !requiredFlag || !!featureFlags[requiredFlag] } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface resourcesAccessControlLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + sortedMembers: OrganizationMemberType[] | null // membersLogic + roles: RoleType[] // roleAccessControlLogic + currentProjectId: number | string // teamLogic + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean // userLogic + addableMembers: OrganizationMemberType[] + addableRoles: RoleType[] + availableLevels: AccessControlLevel[] + canEditRoleBasedAccessControls: boolean | null + defaultAccessLevel: string | null + defaultModalOpen: boolean + defaultResourceAccessControls: DefaultResourceAccessControls + editingMember: MemberResourceAccessControls | null + editingRole: RoleResourceAccessControls | null + memberModalOpen: boolean + memberResourceAccessControls: MemberResourceAccessControls[] + organizationAdmins: OrganizationMemberType[] + resourceAccessControls: AccessControlResponseType | null + resourceAccessControlsLoading: boolean + resources: APIScopeObject[] + roleModalOpen: boolean + roleResourceAccessControls: RoleResourceAccessControls[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface resourcesAccessControlLogicActions { + closeDefaultModal: () => { + value: true + } + closeMemberModal: () => { + value: true + } + closeRoleModal: () => { + value: true + } + loadResourceAccessControls: () => any + loadResourceAccessControlsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadResourceAccessControlsSuccess: ( + resourceAccessControls: AccessControlResponseType, + payload?: any + ) => { + resourceAccessControls: AccessControlResponseType + payload?: any + } + openDefaultModal: () => { + value: true + } + openMemberModal: (editingMember?: MemberResourceAccessControls | null) => { + editingMember: MemberResourceAccessControls | null + } + openRoleModal: (editingRole?: RoleResourceAccessControls | null) => { + editingRole: RoleResourceAccessControls | null + } + updateResourceAccessControls: ( + accessControls: Pick[], + saveType: 'default' | 'member' | 'role' + ) => { + accessControls: Pick[] + saveType: 'default' | 'member' | 'role' + } + updateResourceAccessControlsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + updateResourceAccessControlsSuccess: ( + resourceAccessControls: AccessControlResponseType | null, + payload?: { + accessControls: Pick< + AccessControlUpdateType, + 'access_level' | 'organization_member' | 'resource' | 'role' + >[] + saveType: 'default' | 'member' | 'role' + } + ) => { + resourceAccessControls: AccessControlResponseType | null + payload?: { + accessControls: Pick< + AccessControlUpdateType, + 'access_level' | 'organization_member' | 'resource' | 'role' + >[] + saveType: 'default' | 'member' | 'role' + } + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface resourcesAccessControlLogicMeta { + __keaTypeGenInternalSelectorTypes: { + availableLevels: (resourceAccessControls: AccessControlResponseType | null) => AccessControlLevel[] + defaultAccessLevel: (resourceAccessControls: AccessControlResponseType | null) => string | null + organizationAdmins: (sortedMembers: OrganizationMemberType[] | null) => OrganizationMemberType[] + defaultResourceAccessControls: ( + resourceAccessControls: AccessControlResponseType | null + ) => DefaultResourceAccessControls + addableMembers: ( + sortedMembers: OrganizationMemberType[] | null, + memberResourceAccessControls: MemberResourceAccessControls[], + organizationAdmins: OrganizationMemberType[] + ) => OrganizationMemberType[] + addableRoles: (roles: RoleType[], roleResourceAccessControls: RoleResourceAccessControls[]) => RoleType[] + memberResourceAccessControls: ( + sortedMembers: OrganizationMemberType[] | null, + resourceAccessControls: AccessControlResponseType | null + ) => MemberResourceAccessControls[] + roleResourceAccessControls: ( + roles: RoleType[], + resourceAccessControls: AccessControlResponseType | null + ) => RoleResourceAccessControls[] + resources: ( + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean, + featureFlags: FeatureFlagsSet + ) => APIScopeObject[] + canEditRoleBasedAccessControls: (resourceAccessControls: AccessControlResponseType | null) => boolean | null + } +} + +export type resourcesAccessControlLogicType = MakeLogicType< + resourcesAccessControlLogicValues, + resourcesAccessControlLogicActions, + Record, + resourcesAccessControlLogicMeta +> + export const resourcesAccessControlLogic = kea([ path(['scenes', 'accessControl', 'resourcesAccessControlLogic']), connect(() => ({ @@ -181,28 +315,28 @@ export const resourcesAccessControlLogic = kea( selectors({ availableLevels: [ (s) => [s.resourceAccessControls], - (resourceAccessControls): AccessControlLevel[] => { + (resourceAccessControls: AccessControlResponseType | null): AccessControlLevel[] => { return resourceAccessControls?.available_access_levels ?? [] }, ], defaultAccessLevel: [ (s) => [s.resourceAccessControls], - (resourceAccessControls): string | null => { + (resourceAccessControls: AccessControlResponseType | null): string | null => { return resourceAccessControls?.default_access_level ?? null }, ], organizationAdmins: [ (s) => [s.sortedMembers], - (members): OrganizationMemberType[] => { + (members: OrganizationMemberType[] | null): OrganizationMemberType[] => { return members?.filter((member) => member.level >= OrganizationMembershipLevel.Admin) ?? [] }, ], defaultResourceAccessControls: [ (s) => [s.resourceAccessControls], - (resourceAccessControls): DefaultResourceAccessControls => { + (resourceAccessControls: AccessControlResponseType | null): DefaultResourceAccessControls => { const accessControls = resourceAccessControls?.access_controls ?? [] // Find all acs without a roles (they are the default ones) @@ -309,7 +443,10 @@ export const resourcesAccessControlLogic = kea( resources: [ (s) => [s.hasAvailableFeature, s.featureFlags], - (hasAvailableFeature, featureFlags): APIScopeObject[] => { + ( + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean, + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet + ): APIScopeObject[] => { const allResources = [ AccessControlResourceType.Action, AccessControlResourceType.ActivityLog, @@ -347,7 +484,7 @@ export const resourcesAccessControlLogic = kea( canEditRoleBasedAccessControls: [ (s) => [s.resourceAccessControls], - (resourceAccessControls): boolean | null => { + (resourceAccessControls: AccessControlResponseType | null): boolean | null => { return resourceAccessControls?.user_can_edit_access_levels ?? null }, ], diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/roleAccessControlLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/roleAccessControlLogic.ts index 96f18f30c304..6b4da5090b8f 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/roleAccessControlLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/access_control/roleAccessControlLogic.ts @@ -1,5 +1,6 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { loaders } from 'kea-loaders' import { actionToUrl, router } from 'kea-router' @@ -19,7 +20,7 @@ import { RoleType, } from '~/types' -import type { roleAccessControlLogicType } from './roleAccessControlLogicType' +import type { AvailableFeature } from '../../../../../types' export type DefaultResourceAccessControls = { accessControlByResource: Record @@ -31,6 +32,226 @@ export type RoleResourceAccessControls = DefaultResourceAccessControls & { role?: RoleType } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface roleAccessControlLogicValues { + sortedMembers: OrganizationMemberType[] | null // membersLogic + currentProjectId: number | string // teamLogic + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean // userLogic + canEditRoles: boolean | null + editingRole: { + name: string + } + editingRoleAllErrors: Record + editingRoleChanged: boolean + editingRoleErrors: DeepPartialMap< + { + name: string + }, + ValidationErrorType + > + editingRoleHasErrors: boolean + editingRoleId: string | null + editingRoleManualErrors: Record + editingRoleTouched: boolean + editingRoleTouches: Record + editingRoleValidationErrors: DeepPartialMap< + { + name: string + }, + ValidationErrorType + > + isEditingRoleSubmitting: boolean + isEditingRoleValid: boolean + resourceAccessControls: AccessControlResponseType | null + resourceAccessControlsLoading: boolean + roles: RoleType[] + rolesLoading: boolean + selectedRoleId: string | null + showEditingRoleErrors: boolean + sortedRoles: RoleType[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface roleAccessControlLogicActions { + ensureAllMembersLoaded: () => { + value: true + } // membersLogic + loadCurrentOrganization: () => any // organizationLogic + addMembersToRole: ( + role: RoleType, + members: string[] + ) => { + members: string[] + role: RoleType + } + addMembersToRoleFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + addMembersToRoleSuccess: ( + roles: RoleType[], + payload?: { + members: string[] + role: RoleType + } + ) => { + roles: RoleType[] + payload?: { + members: string[] + role: RoleType + } + } + deleteRole: (roleId: RoleType['id']) => { + roleId: string + } + deleteRoleFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + deleteRoleSuccess: ( + roles: RoleType[], + payload?: { + roleId: string + } + ) => { + roles: RoleType[] + payload?: { + roleId: string + } + } + loadResourceAccessControls: () => any + loadResourceAccessControlsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadResourceAccessControlsSuccess: ( + resourceAccessControls: AccessControlResponseType, + payload?: any + ) => { + resourceAccessControls: AccessControlResponseType + payload?: any + } + loadRoles: () => any + loadRolesFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadRolesSuccess: ( + roles: RoleType[], + payload?: any + ) => { + roles: RoleType[] + payload?: any + } + removeMemberFromRole: ( + role: RoleType, + roleMemberId: string + ) => { + role: RoleType + roleMemberId: string + } + removeMemberFromRoleFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + removeMemberFromRoleSuccess: ( + roles: RoleType[], + payload?: { + role: RoleType + roleMemberId: string + } + ) => { + roles: RoleType[] + payload?: { + role: RoleType + roleMemberId: string + } + } + resetEditingRole: (values?: { name: string }) => { + values?: { + name: string + } + } + selectRoleId: (roleId: RoleType['id'] | null) => { + roleId: string | null + } + setEditingRoleId: (roleId: string | null) => { + roleId: string | null + } + setEditingRoleManualErrors: (errors: Record) => { + errors: Record + } + setEditingRoleValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setEditingRoleValues: ( + values: DeepPartial<{ + name: string + }> + ) => { + values: DeepPartial<{ + name: string + }> + } + submitEditingRole: () => { + value: boolean + } + submitEditingRoleFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitEditingRoleRequest: (editingRole: { name: string }) => { + editingRole: { + name: string + } + } + submitEditingRoleSuccess: (editingRole: { name: string }) => { + editingRole: { + name: string + } + } + touchEditingRoleField: (key: string) => { + key: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface roleAccessControlLogicMeta { + __keaTypeGenInternalSelectorTypes: { + sortedRoles: (roles: RoleType[]) => RoleType[] + canEditRoles: (resourceAccessControls: AccessControlResponseType | null) => boolean | null + } +} + +export type roleAccessControlLogicType = MakeLogicType< + roleAccessControlLogicValues, + roleAccessControlLogicActions, + Record, + roleAccessControlLogicMeta +> + export const roleAccessControlLogic = kea([ path(['scenes', 'accessControl', 'roleAccessControlLogic']), connect(() => ({ diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelActivityLogic.tsx b/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelActivityLogic.tsx index feface92f0b7..8364f11510a6 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelActivityLogic.tsx +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelActivityLogic.tsx @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { lazyLoaders } from 'kea-loaders' import { subscriptions } from 'kea-subscriptions' @@ -13,10 +13,10 @@ import { projectLogic } from 'scenes/projectLogic' import { ActivityScope, UserBasicType } from '~/types' +import type { SidePanelTab } from '../../../../../types' import { sidePanelContextLogic } from '../../sidePanelContextLogic' import { sidePanelStateLogic } from '../../sidePanelStateLogic' import { SidePanelSceneContext } from '../../types' -import type { sidePanelActivityLogicType } from './sidePanelActivityLogicType' // ActivityScope values that should not appear in dropdowns const HIDDEN_ACTIVITY_SCOPES: ActivityScope[] = [ @@ -48,6 +48,101 @@ export enum SidePanelActivityTab { Metalytics = 'metalytics', } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelActivityLogicValues { + currentProjectId: number | null // projectLogic + sceneSidePanelContext: SidePanelSceneContext // sidePanelContextLogic + selectedTabOptions: string | null // sidePanelStateLogic + activeFilters: ActivityFilters | null + activeTab: SidePanelActivityTab + allActivity: HumanizedActivityLogItem[] + allActivityHasNext: boolean + allActivityResponse: PaginatedResponse | null + allActivityResponseLoading: boolean + contextFromPage: ActivityFilters | null + visibleActivityScopes: ActivityScope[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelActivityLogicActions { + openSidePanel: ( + tab: SidePanelTab, + options?: string | undefined + ) => { + options: string | undefined + tab: SidePanelTab + } // sidePanelStateLogic + loadAllActivity: () => { + value: true + } + loadAllActivityFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadAllActivitySuccess: ( + allActivityResponse: PaginatedResponse, + payload?: { + value: true + } + ) => { + allActivityResponse: PaginatedResponse + payload?: { + value: true + } + } + loadOlderActivity: () => { + value: true + } + loadOlderActivityFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadOlderActivitySuccess: ( + allActivityResponse: PaginatedResponse | null, + payload?: { + value: true + } + ) => { + allActivityResponse: PaginatedResponse | null + payload?: { + value: true + } + } + maybeLoadOlderActivity: () => { + value: true + } + setActiveFilters: (filters: ActivityFilters | null) => { + filters: ActivityFilters | null + } + setActiveTab: (tab: SidePanelActivityTab) => { + tab: SidePanelActivityTab + } + setContextFromPage: (filters: ActivityFilters | null) => { + filters: ActivityFilters | null + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelActivityLogicMeta { + __keaTypeGenInternalSelectorTypes: { + allActivity: (allActivityResponse: PaginatedResponse | null) => HumanizedActivityLogItem[] + allActivityHasNext: (allActivityResponse: PaginatedResponse | null) => boolean + } +} + +export type sidePanelActivityLogicType = MakeLogicType< + sidePanelActivityLogicValues, + sidePanelActivityLogicActions, + Record, + sidePanelActivityLogicMeta +> + export const sidePanelActivityLogic = kea([ path(['scenes', 'navigation', 'sidepanel', 'sidePanelActivityLogic']), connect(() => ({ @@ -142,11 +237,14 @@ export const sidePanelActivityLogic = kea([ selectors({ allActivity: [ (s) => [s.allActivityResponse], - (allActivityResponse): HumanizedActivityLogItem[] => { + (allActivityResponse: PaginatedResponse | null): HumanizedActivityLogItem[] => { return humanize(allActivityResponse?.results || [], describerFor, true) }, ], - allActivityHasNext: [(s) => [s.allActivityResponse], (allActivityResponse) => !!allActivityResponse?.next], + allActivityHasNext: [ + (s) => [s.allActivityResponse], + (allActivityResponse: PaginatedResponse | null) => !!allActivityResponse?.next, + ], visibleActivityScopes: [ () => [], (): ActivityScope[] => { diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelNotificationsLogic.tsx b/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelNotificationsLogic.tsx index 5a8cc4937dd0..a36a8c0fc3b4 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelNotificationsLogic.tsx +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/activity/sidePanelNotificationsLogic.tsx @@ -1,4 +1,15 @@ -import { actions, afterMount, beforeUnmount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { + MakeLogicType, + actions, + afterMount, + beforeUnmount, + connect, + kea, + listeners, + path, + reducers, + selectors, +} from 'kea' import { lazyLoaders } from 'kea-loaders' import { router } from 'kea-router' import posthog, { JsonRecord } from 'posthog-js' @@ -41,8 +52,10 @@ import { } from 'products/notifications/frontend/generated/api.schemas' import { RESOURCE_EDITED_EVENT_TYPE, resourceEditedLogic } from 'products/notifications/frontend/resourceEditedLogic' +import type { FeatureFlagsSet } from '../../../../../lib/logic/featureFlagLogic' +import type { OrganizationType, TeamPublicType, TeamType } from '../../../../../types' import { sidePanelContextLogic } from '../../sidePanelContextLogic' -import type { sidePanelNotificationsLogicType } from './sidePanelNotificationsLogicType' +import type { SidePanelSceneContext } from '../../types' const LEGACY_POLL_TIMEOUT = 5 * 60 * 1000 const SSE_RETRY_ATTEMPTS = 3 @@ -152,6 +165,263 @@ export interface ChangelogFlagPayload { email?: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelNotificationsLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + currentOrganization: OrganizationType | null // organizationLogic + currentProjectId: number | null // projectLogic + sceneSidePanelContext: SidePanelSceneContext // sidePanelContextLogic + currentTeam: TeamPublicType | TeamType | null // teamLogic + currentTeamId: number | null // teamLogic + archivedGroups: NotificationGroup[] + archivedListOffset: number + archivedLoaded: boolean + archivedNotifications: InAppNotification[] + archivingEnabled: boolean + errorCounter: number + expandedGroupKeys: Set + groups: NotificationGroup[] + hasArchivableNotifications: boolean + hasMoreArchived: boolean + hasMoreNotifications: boolean + hasNotifications: boolean + hasUnread: boolean + importantChanges: ChangesResponse | null + importantChangesLoading: boolean + inAppNotifications: InAppNotification[] + inAppUnreadCount: number + isInitialLoadComplete: boolean + isLoadingMore: boolean + isLoadingMoreArchived: boolean + legacyNotifications: HumanizedActivityLogItem[] + loadedGroupKeys: Set + loadedUnreadCount: number + loadingGroupKeys: Set + mainListOffset: number + manuallyToggledIds: Set + notifications: HumanizedActivityLogItem[] | InAppNotification[] + projectNameForNotification: (notification: InAppNotification) => string | null + realTimeNotificationsEnabled: boolean + sourcePathForNotification: (notification: InAppNotification) => string | null + unreadCount: number +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelNotificationsLogicActions { + resourceEdited: (event: ResourceEditedEvent) => { + event: ResourceEditedEvent + } // resourceEditedLogic + loadCurrentTeamSuccess: ( + currentTeam: TeamPublicType | null, + payload?: any + ) => { + currentTeam: TeamPublicType | null + payload?: any + } // teamLogic + appendArchivedNotifications: ( + notifications: InAppNotification[], + hasMore: boolean + ) => { + hasMore: boolean + notifications: InAppNotification[] + } + appendInAppNotifications: ( + notifications: InAppNotification[], + hasMore: boolean + ) => { + hasMore: boolean + notifications: InAppNotification[] + } + archiveAll: () => { + value: true + } + archiveGroup: (group: NotificationGroup) => { + group: NotificationGroup + } + archiveNotification: (id: string) => { + id: string + } + clearErrorCount: () => { + value: true + } + incrementErrorCount: () => { + value: true + } + initialLoadDone: () => { + value: true + } + loadArchivedGroupChildren: (group: NotificationGroup) => { + group: NotificationGroup + } + loadArchivedNotifications: () => { + value: true + } + loadGroupChildren: (group: NotificationGroup) => { + group: NotificationGroup + } + loadImportantChanges: (onlyUnread?: any) => { + onlyUnread: any + } + loadImportantChangesFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadImportantChangesSuccess: ( + importantChanges: ChangesResponse | null, + payload?: { + onlyUnread: any + } + ) => { + importantChanges: ChangesResponse | null + payload?: { + onlyUnread: any + } + } + loadMoreArchived: () => { + value: true + } + loadMoreArchivedSuccess: (count: number) => { + count: number + } + loadMoreNotifications: () => { + value: true + } + loadMoreNotificationsSuccess: (count: number) => { + count: number + } + markAllAsRead: () => { + value: true + } + markAllAsReadFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + markAllAsReadSuccess: ( + importantChanges: ChangesResponse | null, + payload?: { + value: true + } + ) => { + importantChanges: ChangesResponse | null + payload?: { + value: true + } + } + markAsRead: (id: string) => { + id: string + } + markGroupChildrenLoaded: (groupKey: string) => { + groupKey: string + } + navigateToNotification: (notification: InAppNotification) => { + notification: InAppNotification + } + notificationReceived: (notification: InAppNotification) => { + notification: InAppNotification + } + refreshInAppUnreadCount: () => { + value: true + } + removeNotifications: (ids: string[]) => { + ids: string[] + } + setArchivedNotifications: ( + notifications: InAppNotification[], + hasMore: boolean + ) => { + hasMore: boolean + notifications: InAppNotification[] + } + setGroupChildrenRead: ( + groupKey: string, + read: boolean + ) => { + groupKey: string + read: boolean + } + setGroupLoading: ( + groupKey: string, + loading: boolean + ) => { + groupKey: string + loading: boolean + } + setInAppNotifications: ( + notifications: InAppNotification[], + hasMore: boolean + ) => { + hasMore: boolean + notifications: InAppNotification[] + } + setInAppUnreadCount: (count: number) => { + count: number + } + startSSE: () => { + value: true + } + stopSSE: () => { + value: true + } + toggleGroupExpanded: (groupKey: string) => { + groupKey: string + } + toggleGroupRead: (group: NotificationGroup) => { + group: NotificationGroup + } + togglePolling: (pageIsVisible: boolean) => { + pageIsVisible: boolean + } + toggleRead: (id: string) => { + id: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelNotificationsLogicMeta { + __keaTypeGenInternalSelectorTypes: { + realTimeNotificationsEnabled: (featureFlags: FeatureFlagsSet) => boolean + archivingEnabled: (featureFlags: FeatureFlagsSet) => boolean + legacyNotifications: (importantChanges: ChangesResponse | null) => HumanizedActivityLogItem[] + notifications: ( + realTimeNotificationsEnabled: boolean, + legacyNotifications: HumanizedActivityLogItem[], + inAppNotifications: InAppNotification[] + ) => HumanizedActivityLogItem[] | InAppNotification[] + hasNotifications: (notifications: HumanizedActivityLogItem[] | InAppNotification[]) => boolean + hasArchivableNotifications: (inAppNotifications: InAppNotification[]) => boolean + unreadCount: ( + realTimeNotificationsEnabled: boolean, + legacyNotifications: HumanizedActivityLogItem[], + inAppUnreadCount: number + ) => number + hasUnread: (unreadCount: number) => boolean + loadedUnreadCount: (inAppNotifications: InAppNotification[]) => number + projectNameForNotification: ( + currentTeamId: number | null, + currentOrganization: OrganizationType | null + ) => (notification: InAppNotification) => string | null + sourcePathForNotification: (featureFlags: FeatureFlagsSet) => (notification: InAppNotification) => string | null + groups: (inAppNotifications: InAppNotification[], loadedGroupKeys: Set) => NotificationGroup[] + archivedGroups: ( + archivedNotifications: InAppNotification[], + loadedGroupKeys: Set + ) => NotificationGroup[] + } +} + +export type sidePanelNotificationsLogicType = MakeLogicType< + sidePanelNotificationsLogicValues, + sidePanelNotificationsLogicActions, + Record, + sidePanelNotificationsLogicMeta +> + export const sidePanelNotificationsLogic = kea([ path(['layout', 'navigation-3000', 'sidepanel', 'panels', 'activity', 'sidePanelNotificationsLogic']), connect(() => ({ @@ -895,15 +1165,17 @@ export const sidePanelNotificationsLogic = kea( selectors({ realTimeNotificationsEnabled: [ (s) => [s.featureFlags], - (featureFlags): boolean => !!featureFlags[FEATURE_FLAGS.REAL_TIME_NOTIFICATIONS], + (featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet): boolean => + !!featureFlags[FEATURE_FLAGS.REAL_TIME_NOTIFICATIONS], ], archivingEnabled: [ (s) => [s.featureFlags], - (featureFlags): boolean => !!featureFlags[FEATURE_FLAGS.CLEARABLE_NOTIFICATIONS], + (featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet): boolean => + !!featureFlags[FEATURE_FLAGS.CLEARABLE_NOTIFICATIONS], ], legacyNotifications: [ (s) => [s.importantChanges], - (importantChanges): HumanizedActivityLogItem[] => { + (importantChanges: ChangesResponse | null): HumanizedActivityLogItem[] => { try { let importantChangesHumanized = humanize(importantChanges?.results || [], describerFor, true) @@ -961,39 +1233,46 @@ export const sidePanelNotificationsLogic = kea( notifications: [ (s) => [s.realTimeNotificationsEnabled, s.legacyNotifications, s.inAppNotifications], ( - realTimeEnabled, - legacyNotifications, - inAppNotifications + realTimeEnabled: boolean, + legacyNotifications: HumanizedActivityLogItem[], + inAppNotifications: InAppNotification[] ): HumanizedActivityLogItem[] | InAppNotification[] => { return realTimeEnabled ? inAppNotifications : legacyNotifications }, ], - hasNotifications: [(s) => [s.notifications], (notifications) => !!notifications.length], + hasNotifications: [ + (s) => [s.notifications], + (notifications: HumanizedActivityLogItem[] | InAppNotification[]) => !!notifications.length, + ], hasArchivableNotifications: [ (s) => [s.inAppNotifications], - (inAppNotifications): boolean => inAppNotifications.some((n) => n.archivable), + (inAppNotifications: InAppNotification[]): boolean => inAppNotifications.some((n) => n.archivable), ], unreadCount: [ (s) => [s.realTimeNotificationsEnabled, s.legacyNotifications, s.inAppUnreadCount], - (realTimeEnabled, legacyNotifications, inAppUnreadCount): number => { + ( + realTimeEnabled: boolean, + legacyNotifications: HumanizedActivityLogItem[], + inAppUnreadCount: number + ): number => { if (realTimeEnabled) { return inAppUnreadCount } return legacyNotifications.filter((ic) => ic.unread).length }, ], - hasUnread: [(s) => [s.unreadCount], (unreadCount) => unreadCount > 0], + hasUnread: [(s) => [s.unreadCount], (unreadCount: number) => unreadCount > 0], // Unread among the rows actually loaded into the panel. The panel's "Mark all as read" // button and Unread tab key off this — not `inAppUnreadCount`, a separately-fetched server // total that's hand-patched at several call sites — so they can never drift from the // visible rows. `inAppUnreadCount` stays the source for the global bell badge. loadedUnreadCount: [ (s) => [s.inAppNotifications], - (inAppNotifications): number => inAppNotifications.filter((n) => !n.read).length, + (inAppNotifications: InAppNotification[]): number => inAppNotifications.filter((n) => !n.read).length, ], projectNameForNotification: [ (s) => [s.currentTeamId, s.currentOrganization], - (currentTeamId, currentOrganization) => { + (currentTeamId: number | null, currentOrganization: null | import('~/types').OrganizationType) => { return (notification: InAppNotification): string | null => { if (notification.team_id === null || notification.team_id === currentTeamId) { return null @@ -1004,7 +1283,7 @@ export const sidePanelNotificationsLogic = kea( ], sourcePathForNotification: [ (s) => [s.featureFlags], - (featureFlags) => + (featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet) => (notification: InAppNotification): string | null => { // When the recap flag is on, the digest links to the recap page instead of the raw dashboard const recapEnabled = !!featureFlags[FEATURE_FLAGS.WEB_ANALYTICS_RECAP] diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/discussion/sidePanelDiscussionLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/discussion/sidePanelDiscussionLogic.ts index 52783c43d2c3..1c66cf70844b 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/discussion/sidePanelDiscussionLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/discussion/sidePanelDiscussionLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { subscriptions } from 'kea-subscriptions' @@ -6,8 +6,100 @@ import api from 'lib/api' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { CommentsLogicProps } from 'scenes/comments/commentsLogic' +import type { FeatureFlagsSet } from '../../../../../lib/logic/featureFlagLogic' import { sidePanelContextLogic } from '../../sidePanelContextLogic' -import type { sidePanelDiscussionLogicType } from './sidePanelDiscussionLogicType' +import type { SidePanelSceneContext } from '../../types' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelDiscussionLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + sceneSidePanelContext: SidePanelSceneContext // sidePanelContextLogic + commentCount: number + commentCountLoading: boolean + commentsListRef: HTMLDivElement | null + commentsLogicProps: CommentsLogicProps | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelDiscussionLogicActions { + incrementCommentCount: () => any + incrementCommentCountFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + incrementCommentCountSuccess: ( + commentCount: number, + payload?: any + ) => { + commentCount: number + payload?: any + } + loadCommentCount: () => { + value: true + } + loadCommentCountFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadCommentCountSuccess: ( + commentCount: number, + payload?: { + value: true + } + ) => { + commentCount: number + payload?: { + value: true + } + } + resetCommentCount: () => { + value: true + } + resetCommentCountFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + resetCommentCountSuccess: ( + commentCount: number, + payload?: { + value: true + } + ) => { + commentCount: number + payload?: { + value: true + } + } + scrollToLastComment: () => { + value: true + } + setCommentsListRef: (ref: HTMLDivElement) => { + ref: HTMLDivElement + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelDiscussionLogicMeta { + __keaTypeGenInternalSelectorTypes: { + commentsLogicProps: (sceneSidePanelContext: SidePanelSceneContext) => CommentsLogicProps | null + } +} + +export type sidePanelDiscussionLogicType = MakeLogicType< + sidePanelDiscussionLogicValues, + sidePanelDiscussionLogicActions, + Record, + sidePanelDiscussionLogicMeta +> export const sidePanelDiscussionLogic = kea([ path(['scenes', 'navigation', 'sidepanel', 'sidePanelDiscussionLogic']), @@ -69,7 +161,7 @@ export const sidePanelDiscussionLogic = kea([ selectors({ commentsLogicProps: [ (s) => [s.sceneSidePanelContext], - (sceneSidePanelContext): CommentsLogicProps | null => { + (sceneSidePanelContext: import('../../types').SidePanelSceneContext): CommentsLogicProps | null => { return sceneSidePanelContext.activity_scope ? { scope: sceneSidePanelContext.activity_scope, diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/exports/sidePanelExportsLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/exports/sidePanelExportsLogic.ts index 08b970a56d1b..0f569ceb4fa1 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/exports/sidePanelExportsLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/exports/sidePanelExportsLogic.ts @@ -1,9 +1,39 @@ -import { afterMount, connect, kea, path } from 'kea' +import { MakeLogicType, afterMount, connect, kea, path } from 'kea' import { exportsLogic } from 'lib/components/ExportButton/exportsLogic' +import type { ExportedAssetType, ExporterFormat, SidePanelTab } from '../../../../../types' import { sidePanelStateLogic } from '../../sidePanelStateLogic' -import type { sidePanelExportsLogicType } from './sidePanelExportsLogicType' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelExportsLogicValues { + assetFormat: ExporterFormat | null // exportsLogic + exports: ExportedAssetType[] // exportsLogic + exportsLoading: boolean // exportsLogic + freshUndownloadedExports: ExportedAssetType[] // exportsLogic +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelExportsLogicActions { + loadExports: () => { + value: true + } // exportsLogic + removeFresh: (exportedAsset: ExportedAssetType) => { + exportedAsset: ExportedAssetType + } // exportsLogic + setAssetFormat: (format: ExporterFormat | null) => { + format: ExporterFormat | null + } // exportsLogic + openSidePanel: ( + tab: SidePanelTab, + options?: string | undefined + ) => { + options: string | undefined + tab: SidePanelTab + } // sidePanelStateLogic +} + +export type sidePanelExportsLogicType = MakeLogicType export const sidePanelExportsLogic = kea([ path(['scenes', 'navigation', 'sidepanel', 'sidePanelExportsLogic']), diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/max/sidePanelMaxAILogic.ts b/frontend/src/layout/navigation-3000/sidepanel/panels/max/sidePanelMaxAILogic.ts index 58a113adcd32..3faca2d3065f 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/max/sidePanelMaxAILogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/max/sidePanelMaxAILogic.ts @@ -1,7 +1,6 @@ -import { actions, kea, listeners, path, reducers } from 'kea' +import { MakeLogicType, actions, kea, listeners, path, reducers } from 'kea' import { loaders } from 'kea-loaders' -import type { sidePanelMaxAILogicType } from './sidePanelMaxAILogicType' import { sidePanelMaxAPI } from './sidePanelMaxAPI' interface RateLimit { @@ -43,6 +42,74 @@ interface RateLimitAction { limitType?: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelMaxAILogicValues { + assistantResponse: string | null + assistantResponseLoading: boolean + currentMessages: ChatMessage[] + hasServerError: boolean + isRateLimited: boolean + isSearchingThinking: boolean + rateLimitType: string | null + retryAfter: number | null + retryAttempts: number +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelMaxAILogicActions { + appendAssistantMessage: (content: string) => { + content: string + } + clearChatHistory: () => { + value: true + } + retryAfter: ( + message: string, + retryAfter: number, + limitType?: string + ) => { + limitType: string | undefined + message: string + retryAfter: number + } + setRateLimited: ( + isLimited: boolean, + limitType?: string + ) => { + isLimited: boolean + limitType: string | undefined + } + setSearchingThinking: (isSearching: boolean) => { + isSearching: boolean + } + setServerError: (isError: boolean) => { + isError: boolean + } + submitMessage: (message: string) => { + message: string + } + submitMessageFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + submitMessageSuccess: ( + assistantResponse: string | null, + payload?: { + message: string + } + ) => { + assistantResponse: string | null + payload?: { + message: string + } + } +} + +export type sidePanelMaxAILogicType = MakeLogicType + export const sidePanelMaxAILogic = kea([ path(['scenes', 'navigation', 'sidepanel', 'sidePanelMaxAILogic']), diff --git a/frontend/src/layout/navigation-3000/sidepanel/sidePanelContextLogic.ts b/frontend/src/layout/navigation-3000/sidepanel/sidePanelContextLogic.ts index 83364fe8f571..10cae195268d 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/sidePanelContextLogic.ts +++ b/frontend/src/layout/navigation-3000/sidepanel/sidePanelContextLogic.ts @@ -1,4 +1,4 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { router } from 'kea-router' import { objectsEqual } from 'kea-test-utils' @@ -6,7 +6,6 @@ import { removeProjectIdIfPresent } from 'lib/utils/kea-router' import { sceneLogic } from 'scenes/sceneLogic' import { SceneConfig } from 'scenes/sceneTypes' -import type { sidePanelContextLogicType } from './sidePanelContextLogicType' import { SidePanelSceneContext } from './types' import { SIDE_PANEL_CONTEXT_KEY } from './types' @@ -26,6 +25,21 @@ export const activityFiltersForScene = (sceneConfig: SceneConfig | null): SidePa return null } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelContextLogicValues { + sceneConfig: SceneConfig | null; // sceneLogic + sceneSidePanelContext: SidePanelSceneContext; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelContextLogicMeta { + __keaTypeGenInternalSelectorTypes: { + sceneSidePanelContext: (sceneConfig: SceneConfig | null, arg: any) => SidePanelSceneContext; + }; +} + +export type sidePanelContextLogicType = MakeLogicType, sidePanelContextLogicMeta>; + export const sidePanelContextLogic = kea([ path(['scenes', 'navigation', 'sidepanel', 'sidePanelContextLogic']), connect(() => ({ @@ -54,7 +68,7 @@ export const sidePanelContextLogic = kea([ return null }, ], - (sceneConfig, context): SidePanelSceneContext => { + (sceneConfig: SceneConfig | null, context): SidePanelSceneContext => { return { ...context, ...(!context?.activity_scope ? activityFiltersForScene(sceneConfig) : {}), diff --git a/frontend/src/layout/navigation-3000/sidepanel/sidePanelLogic.tsx b/frontend/src/layout/navigation-3000/sidepanel/sidePanelLogic.tsx index c31f6205d9b0..f14da97ae7e8 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/sidePanelLogic.tsx +++ b/frontend/src/layout/navigation-3000/sidepanel/sidePanelLogic.tsx @@ -1,4 +1,4 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { combineUrl, router, urlToAction } from 'kea-router' import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic' @@ -9,9 +9,10 @@ import { userLogic } from 'scenes/userLogic' import { sceneLayoutLogic } from '~/layout/scenes/sceneLayoutLogic' import { AvailableFeature, SidePanelTab } from '~/types' +import type { TeamPublicType, TeamType } from '../../../types' import { sidePanelContextLogic } from './sidePanelContextLogic' -import type { sidePanelLogicType } from './sidePanelLogicType' import { sidePanelStateLogic } from './sidePanelStateLogic' +import type { SidePanelSceneContext } from './types' const TABS_REQUIRING_A_TEAM = [ SidePanelTab.Max, @@ -22,6 +23,54 @@ const TABS_REQUIRING_A_TEAM = [ SidePanelTab.Exports, ] +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelLogicValues { + isCloudOrDev: boolean | undefined // preflightLogic + scenePanelIsPresent: boolean // sceneLayoutLogic + sceneSidePanelContext: SidePanelSceneContext // sidePanelContextLogic + selectedTab: SidePanelTab | null // sidePanelStateLogic + sidePanelOpen: boolean // sidePanelStateLogic + currentTeam: TeamPublicType | TeamType | null // teamLogic + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean // userLogic + enabledTabs: SidePanelTab[] + visibleTabs: SidePanelTab[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelLogicActions { + closeSidePanel: (tab?: SidePanelTab | undefined) => { + tab: SidePanelTab | undefined + } // sidePanelStateLogic + openSidePanel: ( + tab: SidePanelTab, + options?: string | undefined + ) => { + options: string | undefined + tab: SidePanelTab + } // sidePanelStateLogic +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelLogicMeta { + __keaTypeGenInternalSelectorTypes: { + enabledTabs: ( + sceneSidePanelContext: SidePanelSceneContext, + currentTeam: TeamPublicType | TeamType | null, + scenePanelIsPresent: boolean, + isCloudOrDev: boolean | undefined, + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean + ) => SidePanelTab[] + visibleTabs: (enabledTabs: SidePanelTab[]) => SidePanelTab[] + } +} + +export type sidePanelLogicType = MakeLogicType< + sidePanelLogicValues, + sidePanelLogicActions, + Record, + sidePanelLogicMeta +> + export const sidePanelLogic = kea([ path(['scenes', 'navigation', 'sidepanel', 'sidePanelLogic']), connect(() => ({ @@ -51,7 +100,13 @@ export const sidePanelLogic = kea([ s.isCloudOrDev, s.hasAvailableFeature, ], - (sceneSidePanelContext, currentTeam, scenePanelIsPresent, isCloudOrDev, hasAvailableFeature) => { + ( + sceneSidePanelContext: import('./types').SidePanelSceneContext, + currentTeam: null | import('~/types').TeamPublicType | import('~/types').TeamType, + scenePanelIsPresent: boolean, + isCloudOrDev: boolean | undefined, + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean + ) => { const tabs: SidePanelTab[] = [] if (scenePanelIsPresent) { @@ -88,7 +143,7 @@ export const sidePanelLogic = kea([ /** Tabs shown in the navigation bar */ visibleTabs: [ (s) => [s.enabledTabs], - (enabledTabs): SidePanelTab[] => { + (enabledTabs: SidePanelTab[]): SidePanelTab[] => { // Some tabs are openable programmatically but not shown in the nav bar const hiddenTabs: SidePanelTab[] = [SidePanelTab.Exports] return enabledTabs.filter((tab) => !hiddenTabs.includes(tab)) diff --git a/frontend/src/layout/navigation-3000/sidepanel/sidePanelStateLogic.tsx b/frontend/src/layout/navigation-3000/sidepanel/sidePanelStateLogic.tsx index 20df423b775a..82c4d70e80a6 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/sidePanelStateLogic.tsx +++ b/frontend/src/layout/navigation-3000/sidepanel/sidePanelStateLogic.tsx @@ -1,11 +1,43 @@ -import { actions, kea, listeners, path, reducers } from 'kea' +import { MakeLogicType, actions, kea, listeners, path, reducers } from 'kea' import { actionToUrl, router, urlToAction } from 'kea-router' import { windowValues } from 'kea-window-values' import posthog from 'posthog-js' import { SidePanelTab } from '~/types' -import type { sidePanelStateLogicType } from './sidePanelStateLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelStateLogicValues { + modalMode: boolean + selectedTab: SidePanelTab | null + selectedTabOptions: string | null + sidePanelAvailable: boolean + sidePanelOpen: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sidePanelStateLogicActions { + closeSidePanel: (tab?: SidePanelTab) => { + tab: SidePanelTab | undefined + } + openSidePanel: ( + tab: SidePanelTab, + options?: string + ) => { + options: string | undefined + tab: SidePanelTab + } + setSidePanelAvailable: (available: boolean) => { + available: boolean + } + setSidePanelOpen: (open: boolean) => { + open: boolean + } + setSidePanelOptions: (options: string | null) => { + options: string | null + } +} + +export type sidePanelStateLogicType = MakeLogicType // The side panel imports a lot of other components so this allows us to avoid circular dependencies diff --git a/frontend/src/layout/navigation/Breadcrumbs/breadcrumbsLogic.tsx b/frontend/src/layout/navigation/Breadcrumbs/breadcrumbsLogic.tsx index 2ef611c0125f..cd5205d3e90f 100644 --- a/frontend/src/layout/navigation/Breadcrumbs/breadcrumbsLogic.tsx +++ b/frontend/src/layout/navigation/Breadcrumbs/breadcrumbsLogic.tsx @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, props, reducers, selectors } from 'kea' import { subscriptions } from 'kea-subscriptions' import { objectsEqual } from 'lib/utils/objects' @@ -13,7 +13,78 @@ import { userLogic } from 'scenes/userLogic' import { Breadcrumb, ProjectTreeRef } from '~/types' -import type { breadcrumbsLogicType } from './breadcrumbsLogicType' +import type { SceneConfig } from '../../../scenes/sceneTypes' +import type { + OrganizationBasicType, + OrganizationType, + PreflightStatus, + ProjectType, + TeamPublicType, + TeamType, + UserType, +} from '../../../types' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface breadcrumbsLogicValues { + currentOrganization: OrganizationType | null; // organizationLogic + preflight: PreflightStatus | null; // preflightLogic + currentProject: ProjectType | null; // projectLogic + activeSceneId: string | null; // sceneLogic + sceneConfig: SceneConfig | null; // sceneLogic + currentTeam: TeamPublicType | TeamType | null; // teamLogic + otherOrganizations: OrganizationBasicType[]; // userLogic + user: UserType | null; // userLogic + actionsContainer: HTMLElement | null; + appBreadcrumbs: Breadcrumb[]; + breadcrumbs: Breadcrumb[]; + documentTitle: string; + firstBreadcrumb: Breadcrumb; + projectTreeRef: ProjectTreeRef | null; + renameState: [ + breadcrumbGlobalKey: string, + tentativeName: string + ] | null; + sceneBreadcrumbKeys: Breadcrumb["key"][]; + sceneBreadcrumbs: Breadcrumb[]; + sceneBreadcrumbsDisplayString: string; + tailBreadcrumbs: Breadcrumb[]; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface breadcrumbsLogicActions { + finishRenaming: () => { + value: true; + }; + setActionsContainer: (element: HTMLElement | null) => { + element: HTMLElement | null; + }; + tentativelyRename: (breadcrumbGlobalKey: string, tentativeName: string) => { + breadcrumbGlobalKey: string; + tentativeName: string; + }; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface breadcrumbsLogicProps { + hashParams: Record; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface breadcrumbsLogicMeta { + __keaTypeGenInternalSelectorTypes: { + sceneBreadcrumbs: (arg: Breadcrumb[]) => Breadcrumb[]; + projectTreeRef: (arg: ProjectTreeRef | null) => ProjectTreeRef | null; + appBreadcrumbs: (preflight: PreflightStatus | null, sceneConfig: SceneConfig | null, activeSceneId: string | null, user: UserType | null, currentProject: ProjectType | null, currentTeam: TeamPublicType | TeamType | null) => Breadcrumb[]; + sceneBreadcrumbKeys: (sceneBreadcrumbs: Breadcrumb[]) => Breadcrumb["key"][]; + breadcrumbs: (appBreadcrumbs: Breadcrumb[], sceneBreadcrumbs: Breadcrumb[]) => Breadcrumb[]; + firstBreadcrumb: (breadcrumbs: Breadcrumb[]) => Breadcrumb; + tailBreadcrumbs: (breadcrumbs: Breadcrumb[]) => Breadcrumb[]; + sceneBreadcrumbsDisplayString: (sceneBreadcrumbs: Breadcrumb[]) => string; + documentTitle: (sceneBreadcrumbs: Breadcrumb[], preflight: PreflightStatus | null) => string; + }; +} + +export type breadcrumbsLogicType = MakeLogicType; export const breadcrumbsLogic = kea([ path(['layout', 'navigation', 'Breadcrumbs', 'breadcrumbsLogic']), @@ -95,7 +166,7 @@ export const breadcrumbsLogic = kea([ return [] }, ], - (crumbs): Breadcrumb[] => crumbs, + (crumbs: Breadcrumb[]): Breadcrumb[] => crumbs, { resultEqualityCheck: objectsEqual }, ], projectTreeRef: [ @@ -121,7 +192,14 @@ export const breadcrumbsLogic = kea([ ], appBreadcrumbs: [ (s) => [s.preflight, s.sceneConfig, s.activeSceneId, s.user, s.currentProject, s.currentTeam], - (preflight, sceneConfig, activeSceneId, user, currentProject, currentTeam) => { + ( + preflight: null | import('~/types').PreflightStatus, + sceneConfig: null | import('../../../scenes/sceneTypes').SceneConfig, + activeSceneId: string | null, + user: null | import('~/types').UserType, + currentProject: null | import('~/types').ProjectType, + currentTeam: null | import('~/types').TeamPublicType | import('~/types').TeamType + ) => { const breadcrumbs: Breadcrumb[] = [] if (!activeSceneId || !sceneConfig) { return breadcrumbs @@ -164,18 +242,19 @@ export const breadcrumbsLogic = kea([ ], sceneBreadcrumbKeys: [ (s) => [s.sceneBreadcrumbs], - (sceneBreadcrumbs): Breadcrumb['key'][] => sceneBreadcrumbs.map((breadcrumb) => breadcrumb.key), + (sceneBreadcrumbs: Breadcrumb[]): Breadcrumb['key'][] => + sceneBreadcrumbs.map((breadcrumb) => breadcrumb.key), ], breadcrumbs: [ (s) => [s.appBreadcrumbs, s.sceneBreadcrumbs], - (appBreadcrumbs, sceneBreadcrumbs): Breadcrumb[] => { + (appBreadcrumbs: Breadcrumb[], sceneBreadcrumbs: Breadcrumb[]): Breadcrumb[] => { return appBreadcrumbs.concat(sceneBreadcrumbs) }, ], - firstBreadcrumb: [(s) => [s.breadcrumbs], (breadcrumbs) => breadcrumbs[0]], + firstBreadcrumb: [(s) => [s.breadcrumbs], (breadcrumbs: Breadcrumb[]) => breadcrumbs[0]], tailBreadcrumbs: [ (s) => [s.breadcrumbs], - (breadcrumbs) => { + (breadcrumbs: Breadcrumb[]) => { const tailBreadcrumbs = breadcrumbs.slice(1) // Remove "path" from the last breadcrumb to disable its link if (tailBreadcrumbs.length > 0) { @@ -186,7 +265,7 @@ export const breadcrumbsLogic = kea([ ], sceneBreadcrumbsDisplayString: [ (s) => [s.sceneBreadcrumbs], - (sceneBreadcrumbs): string => + (sceneBreadcrumbs: Breadcrumb[]): string => sceneBreadcrumbs .filter((breadcrumb) => !!breadcrumb.name) .map((breadcrumb) => breadcrumb.name) @@ -194,7 +273,7 @@ export const breadcrumbsLogic = kea([ ], documentTitle: [ (s) => [s.sceneBreadcrumbs, s.preflight], - (sceneBreadcrumbs, preflight): string => + (sceneBreadcrumbs: Breadcrumb[], preflight: null | import('~/types').PreflightStatus): string => [ ...sceneBreadcrumbs .filter((breadcrumb) => !!breadcrumb.name) diff --git a/frontend/src/layout/navigation/ImpersonationNotice/impersonationNoticeLogic.ts b/frontend/src/layout/navigation/ImpersonationNotice/impersonationNoticeLogic.ts index 7d9ef8852a09..55447aa022f9 100644 --- a/frontend/src/layout/navigation/ImpersonationNotice/impersonationNoticeLogic.ts +++ b/frontend/src/layout/navigation/ImpersonationNotice/impersonationNoticeLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers, selectors } from 'kea' import { urlToAction } from 'kea-router' import { lemonToast } from '@posthog/lemon-ui' @@ -13,7 +13,6 @@ import { userLogic } from 'scenes/userLogic' import { OrganizationMemberType, Region, UserType } from '~/types' import { adminLoginAs } from './adminLoginAs' -import type { impersonationNoticeLogicType } from './impersonationNoticeLogicType' export interface ExpiredSessionInfo { email: string @@ -48,6 +47,130 @@ function adminLoginUrlForRegion(region: Region, email: string): string { return `https://${domain}/admin/posthog/user/?q=${encodeURIComponent(email)}` } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface impersonationNoticeLogicValues { + members: OrganizationMemberType[] | null // membersLogic + membersLoading: boolean // membersLogic + isImpersonationUpgradeInProgress: boolean // userLogic + user: UserType | null // userLogic + adminLoginUrls: AdminLoginUrl[] + changeableMembers: OrganizationMemberType[] + expiredSessionInfo: ExpiredSessionInfo | null + isChangingUser: boolean + isImpersonated: boolean + isMinimized: boolean + isReImpersonating: boolean + isReadOnly: boolean + isSessionExpired: boolean + isUpgradeModalOpen: boolean + pageHiddenAt: number | null + ticketContext: ImpersonationTicketContext | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface impersonationNoticeLogicActions { + ensureAllMembersLoaded: () => { + value: true + } // membersLogic + loadUser: (resetOnFailure?: boolean | undefined) => { + resetOnFailure: boolean | undefined + } // userLogic + loadUserSuccess: ( + user: UserType | null, + payload?: + | { + resetOnFailure: boolean | undefined + } + | undefined + ) => { + payload?: { + resetOnFailure: boolean | undefined + } + user: UserType | null + } // userLogic + upgradeImpersonation: (reason: string) => { + reason: string + } // userLogic + upgradeImpersonationSuccess: ( + user: UserType | null, + payload?: + | { + reason: string + } + | undefined + ) => { + payload?: { + reason: string + } + user: UserType | null + } // userLogic + changeUser: ( + userId: number, + reason?: string + ) => { + reason: string | undefined + userId: number + } + changeUserFailure: (error: string) => { + error: string + } + clearPageHiddenAt: () => { + value: true + } + closeUpgradeModal: () => { + value: true + } + maximize: () => { + value: true + } + minimize: () => { + value: true + } + openUpgradeModal: () => { + value: true + } + reImpersonate: ( + reason: string, + readOnly: boolean + ) => { + readOnly: boolean + reason: string + } + reImpersonateFailure: (error: string) => { + error: string + } + returnToPostHog: () => { + value: true + } + setPageVisible: (visible: boolean) => { + visible: boolean + } + setSessionExpired: (info: ExpiredSessionInfo | null) => { + info: ExpiredSessionInfo | null + } + setTicketContext: (context: ImpersonationTicketContext | null) => { + context: ImpersonationTicketContext | null + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface impersonationNoticeLogicMeta { + __keaTypeGenInternalSelectorTypes: { + isReadOnly: (user: UserType | null) => boolean + isImpersonated: (user: UserType | null) => boolean + adminLoginUrls: (ticketContext: ImpersonationTicketContext | null) => AdminLoginUrl[] + isSessionExpired: (expiredSessionInfo: ExpiredSessionInfo | null) => boolean + changeableMembers: (members: OrganizationMemberType[] | null, user: UserType | null) => OrganizationMemberType[] + } +} + +export type impersonationNoticeLogicType = MakeLogicType< + impersonationNoticeLogicValues, + impersonationNoticeLogicActions, + Record, + impersonationNoticeLogicMeta +> + export const impersonationNoticeLogic = kea([ path(['layout', 'navigation', 'ImpersonationNotice', 'impersonationNoticeLogic']), diff --git a/frontend/src/layout/navigation/SelfReadOnlyNotice/selfReadOnlyModeLogic.ts b/frontend/src/layout/navigation/SelfReadOnlyNotice/selfReadOnlyModeLogic.ts index df65678256b7..39c640cd92c7 100644 --- a/frontend/src/layout/navigation/SelfReadOnlyNotice/selfReadOnlyModeLogic.ts +++ b/frontend/src/layout/navigation/SelfReadOnlyNotice/selfReadOnlyModeLogic.ts @@ -1,4 +1,15 @@ -import { actions, afterMount, beforeUnmount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { + MakeLogicType, + actions, + afterMount, + beforeUnmount, + connect, + kea, + listeners, + path, + reducers, + selectors, +} from 'kea' import posthog from 'posthog-js' import { lemonToast } from '@posthog/lemon-ui' @@ -7,7 +18,7 @@ import { FEATURE_FLAGS } from 'lib/constants' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { setReadOnlyGetter, setReadOnlyNotifier } from 'lib/readOnlyGuard' -import type { selfReadOnlyModeLogicType } from './selfReadOnlyModeLogicType' +import type { FeatureFlagsSet } from '../../../lib/logic/featureFlagLogic' export const ESCALATION_OPTIONS = [ { seconds: 30, label: 'Allow for 30s' }, @@ -31,6 +42,44 @@ export function dropReadOnlyExceptions { + value: true + } + escalate: (durationSeconds: number) => { + durationSeconds: number + } + notifyBlocked: (method: string) => { + method: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface selfReadOnlyModeLogicMeta { + __keaTypeGenInternalSelectorTypes: { + isFlagEnabled: (featureFlags: FeatureFlagsSet) => boolean + isEscalated: (escalatedUntil: number | null) => boolean + isReadOnly: (isFlagEnabled: boolean, isEscalated: boolean) => boolean + } +} + +export type selfReadOnlyModeLogicType = MakeLogicType< + selfReadOnlyModeLogicValues, + selfReadOnlyModeLogicActions, + Record, + selfReadOnlyModeLogicMeta +> + export const selfReadOnlyModeLogic = kea([ path(['layout', 'navigation', 'SelfReadOnlyNotice', 'selfReadOnlyModeLogic']), @@ -57,16 +106,20 @@ export const selfReadOnlyModeLogic = kea([ selectors({ isFlagEnabled: [ (s) => [s.featureFlags], - (featureFlags): boolean => !!featureFlags[FEATURE_FLAGS.READ_ONLY_MODE], + (featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet): boolean => + !!featureFlags[FEATURE_FLAGS.READ_ONLY_MODE], ], // isEscalated reads Date.now() inside a selector — selectors aren't time-reactive. // It only flips back to false when escalatedUntil is reset by the setTimeout in the // `escalate` listener firing `endEscalation`. Acceptable: the timer runs even on // hidden tabs (pauseOnPageHidden: false). - isEscalated: [(s) => [s.escalatedUntil], (until): boolean => until !== null && until > Date.now()], + isEscalated: [ + (s) => [s.escalatedUntil], + (until: number | null): boolean => until !== null && until > Date.now(), + ], isReadOnly: [ (s) => [s.isFlagEnabled, s.isEscalated], - (isFlagEnabled, isEscalated): boolean => isFlagEnabled && !isEscalated, + (isFlagEnabled: boolean, isEscalated: boolean): boolean => isFlagEnabled && !isEscalated, ], }), diff --git a/frontend/src/layout/navigation/navigationLogic.ts b/frontend/src/layout/navigation/navigationLogic.ts index 05a15cb5484d..aa6d76e111e9 100644 --- a/frontend/src/layout/navigation/navigationLogic.ts +++ b/frontend/src/layout/navigation/navigationLogic.ts @@ -1,7 +1,24 @@ -import { actions, kea, path, reducers } from 'kea' +import { MakeLogicType, actions, kea, path, reducers } from 'kea' import { windowValues } from 'kea-window-values' -import type { navigationLogicType } from './navigationLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navigationLogicValues { + fullscreen: boolean + isConfigureHomeModalOpen: boolean + mobileLayout: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navigationLogicActions { + hideConfigureHomeModal: () => { + value: true + } + showConfigureHomeModal: () => { + value: true + } +} + +export type navigationLogicType = MakeLogicType export const navigationLogic = kea([ path(['layout', 'navigation', 'navigationLogic']), diff --git a/frontend/src/layout/navigation/noEventsBannerLogic.ts b/frontend/src/layout/navigation/noEventsBannerLogic.ts index 8e777ce3421c..1df29f4493b2 100644 --- a/frontend/src/layout/navigation/noEventsBannerLogic.ts +++ b/frontend/src/layout/navigation/noEventsBannerLogic.ts @@ -1,11 +1,16 @@ -import { afterMount, connect, kea, path } from 'kea' +import { MakeLogicType, afterMount, connect, kea, path } from 'kea' import { teamLogic } from 'scenes/teamLogic' -import type { noEventsBannerLogicType } from './noEventsBannerLogicType' - const POLL_INTERVAL_MS = 30_000 +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface noEventsBannerLogicActions { + loadCurrentTeam: () => any // teamLogic +} + +export type noEventsBannerLogicType = MakeLogicType<{}, noEventsBannerLogicActions> + export const noEventsBannerLogic = kea([ path(['layout', 'navigation', 'noEventsBannerLogic']), connect(() => ({ diff --git a/frontend/src/layout/navigation/projectNoticeLogic.tsx b/frontend/src/layout/navigation/projectNoticeLogic.tsx index be63c8064f93..9f203f7ca6fa 100644 --- a/frontend/src/layout/navigation/projectNoticeLogic.tsx +++ b/frontend/src/layout/navigation/projectNoticeLogic.tsx @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { router } from 'kea-router' @@ -29,8 +29,6 @@ import { userLogic } from 'scenes/userLogic' import { ProductKey } from '~/queries/schema/schema-general' import { OnboardingStepKey, UserType } from '~/types' -import type { projectNoticeLogicType } from './projectNoticeLogicType' - export type ProjectNoticeVariant = | 'billing_alert' | 'demo_project' @@ -115,6 +113,75 @@ function buildBillingAlertNotice( } } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectNoticeLogicValues { + memberCount: number; // membersLogic + currentOrganizationId: string; // organizationLogic + hasReverseProxy: boolean | null; // reverseProxyCheckerLogic + user: UserType | null; // userLogic + effectiveBillingAlert: BillingAlertConfig | null; + noticeDismissedThisSession: boolean; + projectNotice: ProjectNoticeBlueprint | null; + projectNoticeDismissKey: string | null; + projectNoticeVariant: ProjectNoticeVariant | null; + proxyRecords: ProxyRecord[] | null; + proxyRecordsLoading: boolean; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectNoticeLogicActions { + reportProjectNoticeDismissed: (key: string) => { + key: string; + }; // eventUsageLogic + reportProjectNoticeShown: (variant: string) => { + variant: string; + }; // eventUsageLogic + requestVerificationLink: (uuid: string) => { + uuid: string; + }; // verifyEmailLogic + dismissProjectNotice: (dismissKey: string | null) => { + dismissKey: string | null; + }; + loadRecords: () => any; + loadRecordsFailure: (error: string, errorObject?: any) => { + error: string; + errorObject?: any; + }; + loadRecordsSuccess: (proxyRecords: ProxyRecord[] | null, payload?: any) => { + proxyRecords: ProxyRecord[] | null; + payload?: any; + }; + reportNoticeShown: () => { + value: true; + }; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectNoticeLogicMeta { + __keaTypeGenInternalSelectorTypes: { + effectiveBillingAlert: (billingAlert: BillingAlertConfig | null, fakeBillingAlert: import("lib/components/Superpowers/superpowersLogic").FakeBillingAlert) => BillingAlertConfig | null; + projectNoticeVariant: (currentOrganization: null | import("~/types").OrganizationType, currentTeam: null | import("~/types").TeamPublicType | import("~/types").TeamType, preflight: null | import("~/types").PreflightStatus, isCloudOrDev: boolean | undefined, user: UserType | null, memberCount: number, internetConnectionIssue: boolean, hasProjectNoticeRestriction: boolean, proxyRecords: ProxyRecord[] | null, effectiveBillingAlert: BillingAlertConfig | null, currentLocation: { + hash: string; + hashParams: Record; + method: string; + pathname: string; + search: string; + searchParams: Record; + }, noticeDismissedThisSession: boolean, activeSceneId: string | null, arg: number, hasReverseProxy: boolean | null) => ProjectNoticeVariant | null; + projectNoticeDismissKey: (projectNoticeVariant: ProjectNoticeVariant | null, effectiveBillingAlert: BillingAlertConfig | null) => string | null; + projectNotice: (projectNoticeVariant: ProjectNoticeVariant | null, effectiveBillingAlert: BillingAlertConfig | null, projectNoticeDismissKey: string | null, currentOrganization: null | import("~/types").OrganizationType, user: UserType | null, canAccessBilling: boolean, currentLocation: { + hash: string; + hashParams: Record; + method: string; + pathname: string; + search: string; + searchParams: Record; + }, activeSceneProductKey: ProductKey | null) => ProjectNoticeBlueprint | null; + }; +} + +export type projectNoticeLogicType = MakeLogicType, projectNoticeLogicMeta>; + export const projectNoticeLogic = kea([ path(['layout', 'navigation', 'projectNoticeLogic']), connect(() => ({ @@ -172,7 +239,10 @@ export const projectNoticeLogic = kea([ selectors({ effectiveBillingAlert: [ () => [billingLogic.selectors.billingAlert, superpowersLogic.selectors.fakeBillingAlert], - (billingAlert, fakeBillingAlert): BillingAlertConfig | null => { + ( + billingAlert: BillingAlertConfig | null, + fakeBillingAlert: import('lib/components/Superpowers/superpowersLogic').FakeBillingAlert + ): BillingAlertConfig | null => { if (fakeBillingAlert !== 'none') { return { status: fakeBillingAlert, @@ -203,21 +273,28 @@ export const projectNoticeLogic = kea([ s.hasReverseProxy, ], ( - organization, - currentTeam, - preflight, - isCloudOrDev, - user, - memberCount, - internetConnectionIssue, - hasEventIngestionRestriction, - proxyRecords, - effectiveBillingAlert, - currentLocation, - noticeDismissedThisSession, - activeSceneId, - liveEventCount, - hasReverseProxy + organization: null | import('~/types').OrganizationType, + currentTeam: null | import('~/types').TeamPublicType | import('~/types').TeamType, + preflight: null | import('~/types').PreflightStatus, + isCloudOrDev: boolean | undefined, + user: UserType | null, + memberCount: number, + internetConnectionIssue: boolean, + hasEventIngestionRestriction: boolean, + proxyRecords: ProxyRecord[] | null, + effectiveBillingAlert: BillingAlertConfig | null, + currentLocation: { + hash: string + hashParams: Record + method: string + pathname: string + search: string + searchParams: Record + }, + noticeDismissedThisSession: boolean, + activeSceneId: string | null, + liveEventCount: number, + hasReverseProxy: boolean | null ): ProjectNoticeVariant | null => { if (!organization) { return null @@ -279,7 +356,7 @@ export const projectNoticeLogic = kea([ ], projectNoticeDismissKey: [ (s) => [s.projectNoticeVariant, s.effectiveBillingAlert], - (variant, effectiveBillingAlert): string | null => { + (variant: ProjectNoticeVariant | null, effectiveBillingAlert: BillingAlertConfig | null): string | null => { switch (variant) { case 'billing_alert': return effectiveBillingAlert?.dismissKey @@ -306,14 +383,21 @@ export const projectNoticeLogic = kea([ sceneLogic.selectors.activeSceneProductKey, ], ( - variant, - effectiveBillingAlert, - dismissKey, - currentOrganization, - user, - canAccessBilling, - currentLocation, - activeSceneProductKey + variant: ProjectNoticeVariant | null, + effectiveBillingAlert: BillingAlertConfig | null, + dismissKey: string | null, + currentOrganization: null | import('~/types').OrganizationType, + user: UserType | null, + canAccessBilling: boolean, + currentLocation: { + hash: string + hashParams: Record + method: string + pathname: string + search: string + searchParams: Record + }, + activeSceneProductKey: ProductKey | null ): ProjectNoticeBlueprint | null => { if (!variant) { return null diff --git a/frontend/src/layout/panel-layout/ProjectTree/customProductsLogic.tsx b/frontend/src/layout/panel-layout/ProjectTree/customProductsLogic.tsx index c8f623e1173a..37c3914ee5a1 100644 --- a/frontend/src/layout/panel-layout/ProjectTree/customProductsLogic.tsx +++ b/frontend/src/layout/panel-layout/ProjectTree/customProductsLogic.tsx @@ -1,4 +1,4 @@ -import { kea, path } from 'kea' +import { MakeLogicType, kea, path } from 'kea' import { loaders } from 'kea-loaders' import { lemonToast } from '@posthog/lemon-ui' @@ -8,7 +8,47 @@ import { getAppContext } from 'lib/utils/getAppContext' import type { UserProductListItem } from '~/queries/schema/schema-general' -import type { customProductsLogicType } from './customProductsLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface customProductsLogicValues { + customProducts: UserProductListItem[] + customProductsLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface customProductsLogicActions { + loadCustomProducts: () => any + loadCustomProductsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadCustomProductsSuccess: ( + customProducts: UserProductListItem[], + payload?: any + ) => { + customProducts: UserProductListItem[] + payload?: any + } + seed: () => any + seedFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + seedSuccess: ( + customProducts: UserProductListItem[], + payload?: any + ) => { + customProducts: UserProductListItem[] + payload?: any + } +} + +export type customProductsLogicType = MakeLogicType export const customProductsLogic = kea([ path(['layout', 'panel-layout', 'ProjectTree', 'customProductsLogic']), diff --git a/frontend/src/layout/panel-layout/ProjectTree/menus/recentItemsMenuLogic.ts b/frontend/src/layout/panel-layout/ProjectTree/menus/recentItemsMenuLogic.ts index cb75844496a1..9f15e28e00dc 100644 --- a/frontend/src/layout/panel-layout/ProjectTree/menus/recentItemsMenuLogic.ts +++ b/frontend/src/layout/panel-layout/ProjectTree/menus/recentItemsMenuLogic.ts @@ -1,12 +1,33 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { recentItemsModel } from '~/models/recentItemsModel' import { FileSystemEntry } from '~/queries/schema/schema-general' -import type { recentItemsMenuLogicType } from './recentItemsMenuLogicType' - const RECENT_ITEMS_LIMIT = 10 +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface recentItemsMenuLogicValues { + cachedRecents: FileSystemEntry[] // recentItemsModel + recentsHasLoaded: boolean // recentItemsModel + recentItems: FileSystemEntry[] + recentItemsLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface recentItemsMenuLogicMeta { + __keaTypeGenInternalSelectorTypes: { + recentItems: (cachedRecents: FileSystemEntry[]) => FileSystemEntry[] + recentItemsLoading: (recentsHasLoaded: boolean) => boolean + } +} + +export type recentItemsMenuLogicType = MakeLogicType< + recentItemsMenuLogicValues, + {}, + Record, + recentItemsMenuLogicMeta +> + export const recentItemsMenuLogic = kea([ path(['layout', 'panel-layout', 'ProjectTree', 'menus', 'recentItemsMenuLogic']), connect(() => ({ @@ -15,8 +36,8 @@ export const recentItemsMenuLogic = kea([ selectors({ recentItems: [ (s) => [s.cachedRecents], - (cachedRecents): FileSystemEntry[] => cachedRecents.slice(0, RECENT_ITEMS_LIMIT), + (cachedRecents: FileSystemEntry[]): FileSystemEntry[] => cachedRecents.slice(0, RECENT_ITEMS_LIMIT), ], - recentItemsLoading: [(s) => [s.recentsHasLoaded], (recentsHasLoaded): boolean => !recentsHasLoaded], + recentItemsLoading: [(s) => [s.recentsHasLoaded], (recentsHasLoaded: boolean): boolean => !recentsHasLoaded], }), ]) diff --git a/frontend/src/layout/panel-layout/ProjectTree/projectTreeDataLogic.tsx b/frontend/src/layout/panel-layout/ProjectTree/projectTreeDataLogic.tsx index 6a33fa22411e..d433bf337584 100644 --- a/frontend/src/layout/panel-layout/ProjectTree/projectTreeDataLogic.tsx +++ b/frontend/src/layout/panel-layout/ProjectTree/projectTreeDataLogic.tsx @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { IconDocument, IconFolder, IconPlus } from '@posthog/icons' @@ -43,9 +43,13 @@ import { groupsModel } from '~/models/groupsModel' import { FileSystemEntry, FileSystemIconType, FileSystemImport } from '~/queries/schema/schema-general' import { UserBasicType } from '~/types' +import type { FeatureFlagsSet } from '../../../lib/logic/featureFlagLogic' +import type { Noun } from '../../../models/groupsModel' +import type { UserProductListItem } from '../../../queries/schema/schema-general' +import type { GroupType, GroupTypeIndex, ProjectTreeRef, UserType } from '../../../types' import { panelLayoutLogic } from '../panelLayoutLogic' +import type { PanelLayoutNavIdentifier } from '../panelLayoutLogic' import { customProductsLogic } from './customProductsLogic' -import type { projectTreeDataLogicType } from './projectTreeDataLogicType' const MOVE_ALERT_LIMIT = 50 const DELETE_ALERT_LIMIT = 0 @@ -154,6 +158,370 @@ const humanizeFileSystemEntryType = (type?: string): string => { return humanizedType } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectTreeDataLogicValues { + projectTreeRef: ProjectTreeRef | null // breadcrumbsLogic + customProducts: UserProductListItem[] // customProductsLogic + featureFlags: FeatureFlagsSet // featureFlagLogic + aggregationLabel: (groupTypeIndex: number | null | undefined, deferToUserWording?: boolean) => Noun // groupsModel + groupTypes: Map // groupsModel + groupTypesLoading: boolean // groupsModel + groupsAccessStatus: GroupsAccessStatus // groupsModel + user: UserType | null // userLogic + folderLoadOffset: Record + folderStates: Record + folders: Record + getCustomProductTreeItems: (searchTerm: string) => TreeDataItem[] + getShortcutTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[] + getStaticTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[] + groupItems: FileSystemImport[] + itemsByHref: Record + itemsByPath: Record + itemsByRef: Record + lastNewFolder: string | null + loadingPaths: Record + pendingActions: ProjectTreeAction[] + pendingLoader: boolean + pendingLoaderLoading: boolean + projectTreeRefEntry: FileSystemEntry | null + savedItems: FileSystemEntry[] + savedItemsLoading: boolean + shortcutData: FileSystemEntry[] + shortcutDataHasLoaded: boolean + shortcutDataLoading: boolean + shortcutEntryIdMap: Map + shortcutNonFolderPaths: Set + sortedItems: FileSystemEntry[] + treeItemsNew: TreeDataItem[] + unfiledItems: boolean + unfiledItemsLoading: boolean + users: Record + viableItems: FileSystemEntry[] + viableItemsById: Record +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectTreeDataLogicActions { + setActivePanelIdentifier: (identifier: PanelLayoutNavIdentifier) => { + identifier: PanelLayoutNavIdentifier + } // panelLayoutLogic + addLoadedResults: (results: RecentResults | SearchResults) => { + results: RecentResults | SearchResults + } + addLoadedUsers: (users: UserBasicType[]) => { + users: UserBasicType[] + } + addShortcutItem: (item: FileSystemEntry) => { + item: FileSystemEntry + } + addShortcutItemFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + addShortcutItemSuccess: ( + shortcutData: FileSystemEntry[], + payload?: { + item: FileSystemEntry + } + ) => { + shortcutData: FileSystemEntry[] + payload?: { + item: FileSystemEntry + } + } + createSavedItem: (savedItem: FileSystemEntry) => { + savedItem: FileSystemEntry + } + deleteItem: ( + item: FileSystemEntry, + projectTreeLogicKey: string + ) => { + item: FileSystemEntry + projectTreeLogicKey: string + } + deleteSavedItem: (savedItem: FileSystemEntry) => { + savedItem: FileSystemEntry + } + deleteShortcut: (id: FileSystemEntry['id']) => { + id: string + } + deleteShortcutFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + deleteShortcutSuccess: ( + shortcutData: FileSystemEntry[], + payload?: { + id: string + } + ) => { + shortcutData: FileSystemEntry[] + payload?: { + id: string + } + } + deleteTypeAndRef: ( + type: string, + ref: string + ) => { + ref: string + type: string + } + linkItem: ( + oldPath: string, + newPath: string, + force: boolean, + projectTreeLogicKey: string + ) => { + force: boolean + newPath: string + oldPath: string + projectTreeLogicKey: string + } + loadFolder: ( + folder: string, + forceReload?: boolean + ) => { + folder: string + forceReload: boolean + } + loadFolderFailure: ( + folder: string, + error: string + ) => { + error: string + folder: string + } + loadFolderIfNotLoaded: (folderId: string) => { + folderId: string + } + loadFolderStart: ( + folder: string, + forceReload?: boolean + ) => { + folder: string + forceReload: boolean + } + loadFolderSuccess: ( + folder: string, + entries: FileSystemEntry[], + hasMore: boolean, + offsetIncrease: number, + forceReload?: boolean + ) => { + entries: FileSystemEntry[] + folder: string + forceReload: boolean + hasMore: boolean + offsetIncrease: number + } + loadShortcuts: () => { + value: true + } + loadShortcutsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadShortcutsSuccess: ( + shortcutData: FileSystemEntry[], + payload?: { + value: true + } + ) => { + shortcutData: FileSystemEntry[] + payload?: { + value: true + } + } + loadUnfiledItems: () => { + value: true + } + loadUnfiledItemsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadUnfiledItemsSuccess: ( + unfiledItems: boolean, + payload?: { + value: true + } + ) => { + unfiledItems: boolean + payload?: { + value: true + } + } + moveItem: ( + item: FileSystemEntry, + newPath: string, + force: boolean, + projectTreeLogicKey: string + ) => { + force: boolean + item: FileSystemEntry + newPath: string + projectTreeLogicKey: string + } + movedItem: ( + item: FileSystemEntry, + oldPath: string, + newPath: string + ) => { + item: FileSystemEntry + newPath: string + oldPath: string + } + pruneClosedFolders: (expandedFolders: string[]) => { + expandedFolders: string[] + } + queueAction: ( + action: ProjectTreeAction, + projectTreeLogicKey: string + ) => { + action: ProjectTreeAction + projectTreeLogicKey: string + } + queueActionFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + queueActionSuccess: ( + pendingLoader: boolean, + payload?: { + action: ProjectTreeAction + projectTreeLogicKey: string + } + ) => { + pendingLoader: boolean + payload?: { + action: ProjectTreeAction + projectTreeLogicKey: string + } + } + removeQueuedAction: (action: ProjectTreeAction) => { + action: ProjectTreeAction + } + reorderShortcutByDrag: ( + activeTreeId: string, + overTreeId: string, + position: 'after' | 'before' + ) => { + activeTreeId: string + overTreeId: string + position: 'after' | 'before' + } + reorderShortcuts: (orderedIds: NonNullable[]) => { + orderedIds: string[] + } + reorderShortcutsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + reorderShortcutsSuccess: ( + shortcutData: FileSystemEntry[], + payload?: { + orderedIds: string[] + } + ) => { + shortcutData: FileSystemEntry[] + payload?: { + orderedIds: string[] + } + } + restoredItems: () => { + value: true + } + setLastNewFolder: (folder: string | null) => { + folder: string | null + } + syncTypeAndRef: ( + type: string, + ref: string + ) => { + ref: string + type: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectTreeDataLogicMeta { + __keaTypeGenInternalSelectorTypes: { + savedItems: (folders: Record) => FileSystemEntry[] + shortcutEntryIdMap: (shortcutData: FileSystemEntry[]) => Map + savedItemsLoading: (folderStates: Record) => boolean + viableItems: (savedItems: FileSystemEntry[], pendingActions: ProjectTreeAction[]) => FileSystemEntry[] + sortedItems: (viableItems: FileSystemEntry[]) => FileSystemEntry[] + itemsByRef: (sortedItems: FileSystemEntry[]) => Record + itemsByHref: (sortedItems: FileSystemEntry[]) => Record + itemsByPath: (sortedItems: FileSystemEntry[]) => Record + viableItemsById: (viableItems: FileSystemEntry[]) => Record + loadingPaths: ( + unfiledItemsLoading: boolean, + savedItemsLoading: boolean, + pendingLoaderLoading: boolean, + pendingActions: ProjectTreeAction[] + ) => Record + projectTreeRefEntry: ( + projectTreeRef: ProjectTreeRef | null, + sortedItems: FileSystemEntry[] + ) => FileSystemEntry | null + groupItems: ( + groupTypes: Map, + groupsAccessStatus: GroupsAccessStatus, + aggregationLabel: (groupTypeIndex: number | null | undefined, deferToUserWording?: boolean) => Noun, + shortcutData: FileSystemEntry[], + featureFlags: FeatureFlagsSet + ) => FileSystemImport[] + getShortcutTreeItems: ( + shortcutData: FileSystemEntry[], + viableItems: FileSystemEntry[], + folderStates: Record, + users: Record, + featureFlags: FeatureFlagsSet + ) => (searchTerm: string, onlyFolders: boolean) => TreeDataItem[] + getStaticTreeItems: ( + featureFlags: FeatureFlagsSet, + getShortcutTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[], + groupItems: FileSystemImport[] + ) => (searchTerm: string, onlyFolders: boolean) => TreeDataItem[] + treeItemsNew: ( + getStaticTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[] + ) => TreeDataItem[] + shortcutNonFolderPaths: (shortcutData: FileSystemEntry[]) => Set + getCustomProductTreeItems: ( + customProducts: UserProductListItem[], + featureFlags: FeatureFlagsSet, + folderStates: Record, + users: Record + ) => (searchTerm: string) => TreeDataItem[] + } +} + +export type projectTreeDataLogicType = MakeLogicType< + projectTreeDataLogicValues, + projectTreeDataLogicActions, + Record, + projectTreeDataLogicMeta +> + export const projectTreeDataLogic = kea([ path(['layout', 'panel-layout', 'ProjectTree', 'projectTreeDataLogic']), connect(() => ({ @@ -759,7 +1127,7 @@ export const projectTreeDataLogic = kea([ selectors({ savedItems: [ (s) => [s.folders], - (folders): FileSystemEntry[] => + (folders: Record): FileSystemEntry[] => Object.entries(folders).reduce((acc, [_, items]) => acc.concat(items), [] as FileSystemEntry[]), ], // Maps each top-level Starred row's tree id to the underlying FileSystemEntry id, so the @@ -768,7 +1136,7 @@ export const projectTreeDataLogic = kea([ // intentionally excluded. shortcutEntryIdMap: [ (s) => [s.shortcutData], - (shortcutData): Map => { + (shortcutData: FileSystemEntry[]): Map => { const map = new Map() for (const shortcut of shortcutData) { if (!shortcut.id) { @@ -783,12 +1151,13 @@ export const projectTreeDataLogic = kea([ ], savedItemsLoading: [ (s) => [s.folderStates], - (folderStates): boolean => Object.values(folderStates).some((state) => state === 'loading'), + (folderStates: Record): boolean => + Object.values(folderStates).some((state) => state === 'loading'), ], viableItems: [ // Combine savedItems with pendingActions (s) => [s.savedItems, s.pendingActions], - (savedItems, pendingActions): FileSystemEntry[] => { + (savedItems: FileSystemEntry[], pendingActions: ProjectTreeAction[]): FileSystemEntry[] => { const initialItems = [...savedItems] const itemsByPath = initialItems.reduce( (acc, item) => { @@ -864,11 +1233,11 @@ export const projectTreeDataLogic = kea([ ], sortedItems: [ (s) => [s.viableItems], - (viableItems): FileSystemEntry[] => [...viableItems].sort(sortFilesAndFolders), + (viableItems: FileSystemEntry[]): FileSystemEntry[] => [...viableItems].sort(sortFilesAndFolders), ], itemsByRef: [ (s) => [s.sortedItems], - (sortedItems): Record => { + (sortedItems: FileSystemEntry[]): Record => { const keyedByRef: Record = {} for (const item of sortedItems) { @@ -882,7 +1251,7 @@ export const projectTreeDataLogic = kea([ ], itemsByHref: [ (s) => [s.sortedItems], - (sortedItems): Record => { + (sortedItems: FileSystemEntry[]): Record => { const keyedByHref: Record = {} for (const item of sortedItems) { @@ -896,7 +1265,7 @@ export const projectTreeDataLogic = kea([ ], itemsByPath: [ (s) => [s.sortedItems], - (sortedItems): Record => { + (sortedItems: FileSystemEntry[]): Record => { const keyedByPath: Record = {} for (const item of sortedItems) { @@ -910,7 +1279,7 @@ export const projectTreeDataLogic = kea([ ], viableItemsById: [ (s) => [s.viableItems], - (viableItems): Record => + (viableItems: FileSystemEntry[]): Record => viableItems.reduce( (acc, item) => Object.assign(acc, { @@ -922,7 +1291,12 @@ export const projectTreeDataLogic = kea([ loadingPaths: [ // Paths that are currently being loaded (s) => [s.unfiledItemsLoading, s.savedItemsLoading, s.pendingLoaderLoading, s.pendingActions], - (unfiledItemsLoading, savedItemsLoading, pendingLoaderLoading, pendingActions) => { + ( + unfiledItemsLoading: boolean, + savedItemsLoading: boolean, + pendingLoaderLoading: boolean, + pendingActions: ProjectTreeAction[] + ) => { const loadingPaths: Record = {} if (unfiledItemsLoading) { loadingPaths['Unfiled'] = true @@ -939,7 +1313,10 @@ export const projectTreeDataLogic = kea([ ], projectTreeRefEntry: [ (s) => [s.projectTreeRef, s.sortedItems], - (projectTreeRef, sortedItems): FileSystemEntry | null => { + ( + projectTreeRef: null | import('~/types').ProjectTreeRef, + sortedItems: FileSystemEntry[] + ): FileSystemEntry | null => { if (!projectTreeRef || !projectTreeRef.type || !projectTreeRef.ref) { return null } @@ -953,7 +1330,16 @@ export const projectTreeDataLogic = kea([ ], groupItems: [ (s) => [s.groupTypes, s.groupsAccessStatus, s.aggregationLabel, s.shortcutData, s.featureFlags], - (groupTypes, groupsAccessStatus, aggregationLabel, shortcutData, featureFlags): FileSystemImport[] => { + ( + groupTypes: Map, + groupsAccessStatus: GroupsAccessStatus, + aggregationLabel: ( + groupTypeIndex: number | null | undefined, + deferToUserWording?: boolean + ) => import('~/models/groupsModel').Noun, + shortcutData: FileSystemEntry[], + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet + ): FileSystemImport[] => { const showGroupsIntroductionPage = [ GroupsAccessStatus.HasAccess, GroupsAccessStatus.HasGroupTypes, @@ -1002,11 +1388,11 @@ export const projectTreeDataLogic = kea([ getShortcutTreeItems: [ (s) => [s.shortcutData, s.viableItems, s.folderStates, s.users, s.featureFlags], ( - shortcutData, - viableItems, - folderStates, - users, - featureFlags + shortcutData: FileSystemEntry[], + viableItems: FileSystemEntry[], + folderStates: Record, + users: Record, + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet ): ((searchTerm: string, onlyFolders: boolean) => TreeDataItem[]) => { return function getStaticItems(searchTerm: string, onlyFolders: boolean): TreeDataItem[] { const newShortcutData = [] @@ -1076,9 +1462,9 @@ export const projectTreeDataLogic = kea([ getStaticTreeItems: [ (s) => [s.featureFlags, s.getShortcutTreeItems, s.groupItems], ( - featureFlags, - getShortcutTreeItems, - groupItems + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + getShortcutTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[], + groupItems: FileSystemImport[] ): ((searchTerm: string, onlyFolders: boolean) => TreeDataItem[]) => { const convert = ( imports: FileSystemImport[], @@ -1131,16 +1517,22 @@ export const projectTreeDataLogic = kea([ ], treeItemsNew: [ (s) => [s.getStaticTreeItems], - (getStaticTreeItems) => getStaticTreeItems('', false).find((item) => item.id === 'new://')?.children ?? [], + (getStaticTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[]) => + getStaticTreeItems('', false).find((item) => item.id === 'new://')?.children ?? [], ], shortcutNonFolderPaths: [ (s) => [s.shortcutData], - (shortcutData) => + (shortcutData: FileSystemEntry[]) => new Set(shortcutData.filter((shortcut) => shortcut.type !== 'folder').map((shortcut) => shortcut.path)), ], getCustomProductTreeItems: [ (s) => [s.customProducts, s.featureFlags, s.folderStates, s.users], - (customProducts, featureFlags, folderStates, users): ((searchTerm: string) => TreeDataItem[]) => { + ( + customProducts: import('~/queries/schema/schema-general').UserProductListItem[], + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + folderStates: Record, + users: Record + ): ((searchTerm: string) => TreeDataItem[]) => { return function getCustomProductItems(searchTerm: string): TreeDataItem[] { const allProducts = getDefaultTreeProducts() const productMap = new Map(allProducts.map((p) => [p.path, p])) diff --git a/frontend/src/layout/panel-layout/ProjectTree/projectTreeLogic.tsx b/frontend/src/layout/panel-layout/ProjectTree/projectTreeLogic.tsx index 2c7b261b0aba..b9900c350246 100644 --- a/frontend/src/layout/panel-layout/ProjectTree/projectTreeLogic.tsx +++ b/frontend/src/layout/panel-layout/ProjectTree/projectTreeLogic.tsx @@ -1,4 +1,17 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, propsChanged, reducers, selectors } from 'kea' +import { + MakeLogicType, + actions, + afterMount, + connect, + kea, + key, + listeners, + path, + props, + propsChanged, + reducers, + selectors, +} from 'kea' import { loaders } from 'kea-loaders' import { subscriptions } from 'kea-subscriptions' @@ -15,8 +28,10 @@ import { PAGINATION_LIMIT, projectTreeDataLogic } from '~/layout/panel-layout/Pr import { FileSystemEntry } from '~/queries/schema/schema-general' import { ProjectTreeRef } from '~/types' +import type { Breadcrumb, UserBasicType } from '../../../types' import { panelLayoutLogic } from '../panelLayoutLogic' -import type { projectTreeLogicType } from './projectTreeLogicType' +import type { PanelLayoutNavIdentifier } from '../panelLayoutLogic' +import type { FolderState, ProjectTreeAction } from './types' import { convertFileSystemEntryToTreeDataItem, findInProjectTree, @@ -61,6 +76,417 @@ const FOLDER_LOADING = [ } as TreeDataItem, ] +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectTreeLogicValues { + appBreadcrumbs: Breadcrumb[] // breadcrumbsLogic + projectTreeRef: ProjectTreeRef | null // breadcrumbsLogic + sceneBreadcrumbs: Breadcrumb[] // breadcrumbsLogic + folderLoadOffset: Record // projectTreeDataLogic + folderStates: Record // projectTreeDataLogic + folders: Record // projectTreeDataLogic + getCustomProductTreeItems: (searchTerm: string) => TreeDataItem[] // projectTreeDataLogic + getStaticTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[] // projectTreeDataLogic + lastNewFolder: string | null // projectTreeDataLogic + loadingPaths: Record // projectTreeDataLogic + shortcutData: FileSystemEntry[] // projectTreeDataLogic + sortedItems: FileSystemEntry[] // projectTreeDataLogic + users: Record // projectTreeDataLogic + viableItems: FileSystemEntry[] // projectTreeDataLogic + viableItemsById: Record // projectTreeDataLogic + checkedItemCountNumeric: number + checkedItems: Record + checkedItemsArray: FileSystemEntry[] + checkedItemsCount: string + editingItemId: string + expandedFolders: string[] + expandedSearchFolders: string[] + fullFileSystem: TreeDataItem[] + fullFileSystemFiltered: TreeDataItem[] + helpNoticeVisible: boolean + lastCheckedItem: { + checked: boolean + id: string + shift: boolean + } | null + lastViewedId: string + onlyFolders: boolean + projectTree: TreeDataItem[] + projectTreeItems: TreeDataItem[] + recentResults: RecentResults + recentResultsLoading: boolean + recentTreeItems: TreeDataItem[] + scrollTargetId: string + searchResults: SearchResults + searchResultsLoading: boolean + searchTerm: string + searchTreeItems: TreeDataItem[] + selectMode: LemonTreeSelectMode + sortMethod: ProjectTreeSortMethod + treeTableColumnOffsets: number[] + treeTableColumnSizes: number[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectTreeLogicActions { + resetPanelLayout: (keyboardAction: boolean) => { + keyboardAction: boolean + } // panelLayoutLogic + setActivePanelIdentifier: (identifier: PanelLayoutNavIdentifier) => { + identifier: PanelLayoutNavIdentifier + } // panelLayoutLogic + addLoadedResults: (results: RecentResults | SearchResults) => { + results: RecentResults | SearchResults + } // projectTreeDataLogic + addLoadedUsers: (users: UserBasicType[]) => { + users: UserBasicType[] + } // projectTreeDataLogic + createSavedItem: (savedItem: FileSystemEntry) => { + savedItem: FileSystemEntry + } // projectTreeDataLogic + deleteItem: ( + item: FileSystemEntry, + projectTreeLogicKey: string + ) => { + item: FileSystemEntry + projectTreeLogicKey: string + } // projectTreeDataLogic + deleteSavedItem: (savedItem: FileSystemEntry) => { + savedItem: FileSystemEntry + } // projectTreeDataLogic + deleteTypeAndRef: ( + type: string, + ref: string + ) => { + ref: string + type: string + } // projectTreeDataLogic + linkItem: ( + oldPath: string, + newPath: string, + force: boolean, + projectTreeLogicKey: string + ) => { + force: boolean + newPath: string + oldPath: string + projectTreeLogicKey: string + } // projectTreeDataLogic + loadFolder: ( + folder: string, + forceReload?: boolean | undefined + ) => { + folder: string + forceReload: boolean + } // projectTreeDataLogic + loadFolderIfNotLoaded: (folderId: string) => { + folderId: string + } // projectTreeDataLogic + loadFolderStart: ( + folder: string, + forceReload?: boolean | undefined + ) => { + folder: string + forceReload: boolean + } // projectTreeDataLogic + loadFolderSuccess: ( + folder: string, + entries: FileSystemEntry[], + hasMore: boolean, + offsetIncrease: number, + forceReload?: boolean | undefined + ) => { + entries: FileSystemEntry[] + folder: string + forceReload: boolean + hasMore: boolean + offsetIncrease: number + } // projectTreeDataLogic + moveItem: ( + item: FileSystemEntry, + newPath: string, + force: boolean, + projectTreeLogicKey: string + ) => { + force: boolean + item: FileSystemEntry + newPath: string + projectTreeLogicKey: string + } // projectTreeDataLogic + movedItem: ( + item: FileSystemEntry, + oldPath: string, + newPath: string + ) => { + item: FileSystemEntry + newPath: string + oldPath: string + } // projectTreeDataLogic + pruneClosedFolders: (expandedFolders: string[]) => { + expandedFolders: string[] + } // projectTreeDataLogic + queueAction: ( + action: ProjectTreeAction, + projectTreeLogicKey: string + ) => { + action: ProjectTreeAction + projectTreeLogicKey: string + } // projectTreeDataLogic + addFolder: ( + folder: string, + editAfter?: any, + callback?: (folder: string) => void + ) => { + callback: ((folder: string) => void) | undefined + editAfter: any + folder: string + } + assureVisibility: (projectTreeRef: ProjectTreeRef) => { + projectTreeRef: ProjectTreeRef + } + checkSelectedFolders: () => { + value: true + } + clearScrollTarget: () => { + value: true + } + clearSearch: () => { + value: true + } + createFolder: ( + parentPath: string, + editAfter?: any, + callback?: (folder: string) => void + ) => { + callback: ((folder: string) => void) | undefined + editAfter: any + parentPath: string + } + deleteCheckedItems: () => { + value: true + } + expandProjectFolder: (path: string) => { + path: string + } + linkCheckedItems: (path: string) => { + path: string + } + loadRecentResults: (type: 'end' | 'start') => { + type: 'end' | 'start' + } + loadRecentResultsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadRecentResultsSuccess: ( + recentResults: { + endTime: string | null + hasMore: boolean + results: FileSystemEntry[] + startTime: string | null + }, + payload?: { + type: 'end' | 'start' + } + ) => { + recentResults: { + endTime: string | null + hasMore: boolean + results: FileSystemEntry[] + startTime: string | null + } + payload?: { + type: 'end' | 'start' + } + } + loadSearchResults: ( + searchTerm: string, + offset?: any + ) => { + offset: any + searchTerm: string + } + loadSearchResultsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadSearchResultsSuccess: ( + searchResults: { + hasMore: boolean + lastCount: number + results: FileSystemEntry[] + searchTerm: string + }, + payload?: { + offset: any + searchTerm: string + } + ) => { + searchResults: { + hasMore: boolean + lastCount: number + results: FileSystemEntry[] + searchTerm: string + } + payload?: { + offset: any + searchTerm: string + } + } + moveCheckedItems: (path: string) => { + path: string + } + onItemChecked: ( + id: string, + checked: boolean, + shift: boolean + ) => { + checked: boolean + id: string + shift: boolean + } + rename: ( + value: string, + item: FileSystemEntry + ) => { + item: FileSystemEntry + value: string + } + scrollToView: (item: FileSystemEntry) => { + item: FileSystemEntry + } + setCheckedItems: (checkedItems: Record) => { + checkedItems: Record + } + setEditingItemId: (id: string) => { + id: string + } + setExpandedFolders: (folderIds: string[]) => { + folderIds: string[] + } + setExpandedSearchFolders: (folderIds: string[]) => { + folderIds: string[] + } + setHelpNoticeVisibility: (visible: boolean) => { + visible: boolean + } + setLastCheckedItem: ( + id: string, + checked: boolean, + shift: boolean + ) => { + checked: boolean + id: string + shift: boolean + } + setLastViewedId: (id: string) => { + id: string + } + setOnlyFolders: (onlyFolders: boolean) => { + onlyFolders: boolean + } + setSearchTerm: (searchTerm: string) => { + searchTerm: string + } + setSelectMode: (selectMode: LemonTreeSelectMode) => { + selectMode: LemonTreeSelectMode + } + setSortMethod: (sortMethod: ProjectTreeSortMethod) => { + sortMethod: ProjectTreeSortMethod + } + setTreeTableColumnSizes: (sizes: number[]) => { + sizes: number[] + } + toggleFolderOpen: ( + folderId: string, + isExpanded: boolean + ) => { + folderId: string + isExpanded: boolean + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface projectTreeLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + projectTree: ( + viableItems: FileSystemEntry[], + folderStates: Record, + checkedItems: Record, + users: Record, + onlyFolders: boolean + ) => TreeDataItem[] + recentTreeItems: ( + recentResults: RecentResults, + recentResultsLoading: boolean, + folderStates: Record, + checkedItems: Record, + users: Record + ) => TreeDataItem[] + searchTreeItems: ( + searchResults: SearchResults, + searchResultsLoading: boolean, + folderStates: Record, + checkedItems: Record, + sortMethod: ProjectTreeSortMethod, + onlyFolders: boolean, + users: Record + ) => TreeDataItem[] + projectTreeItems: ( + searchTerm: string, + searchTreeItems: TreeDataItem[], + projectTree: TreeDataItem[], + loadingPaths: Record, + recentTreeItems: TreeDataItem[], + sortMethod: ProjectTreeSortMethod + ) => TreeDataItem[] + fullFileSystem: ( + searchTerm: string, + searchTreeItems: TreeDataItem[], + searchResultsLoading: boolean, + projectTree: TreeDataItem[], + loadingPaths: Record, + recentTreeItems: TreeDataItem[], + recentResultsLoading: boolean, + sortMethod: ProjectTreeSortMethod, + onlyFolders: boolean, + getStaticTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[], + getCustomProductTreeItems: (searchTerm: string) => TreeDataItem[], + arg: any + ) => TreeDataItem[] + fullFileSystemFiltered: ( + fullFileSystem: TreeDataItem[], + searchTerm: string, + arg: any, + arg2: any, + arg3: any + ) => TreeDataItem[] + treeTableColumnOffsets: (treeTableColumnSizes: number[]) => number[] + checkedItemCountNumeric: (checkedItems: Record) => number + checkedItemsCount: ( + checkedItems: Record, + viableItemsById: Record + ) => string + checkedItemsArray: ( + checkedItems: Record, + viableItemsById: Record + ) => FileSystemEntry[] + } +} + +export type projectTreeLogicType = MakeLogicType< + projectTreeLogicValues, + projectTreeLogicActions, + ProjectTreeLogicProps, + projectTreeLogicMeta +> + export const projectTreeLogic = kea([ path(['layout', 'navigation-3000', 'components', 'projectTreeLogic']), props({} as ProjectTreeLogicProps), @@ -443,7 +869,13 @@ export const projectTreeLogic = kea([ selectors({ projectTree: [ (s) => [s.viableItems, s.folderStates, s.checkedItems, s.users, s.onlyFolders], - (viableItems, folderStates, checkedItems, users, onlyFolders): TreeDataItem[] => { + ( + viableItems: FileSystemEntry[], + folderStates: Record, + checkedItems: Record, + users: Record, + onlyFolders: boolean + ): TreeDataItem[] => { const children = convertFileSystemEntryToTreeDataItem({ imports: viableItems.map((i) => ({ ...i, protocol: 'project://' })), folderStates, @@ -459,7 +891,13 @@ export const projectTreeLogic = kea([ ], recentTreeItems: [ (s) => [s.recentResults, s.recentResultsLoading, s.folderStates, s.checkedItems, s.users], - (recentResults, recentResultsLoading, folderStates, checkedItems, users): TreeDataItem[] => { + ( + recentResults: RecentResults, + recentResultsLoading: boolean, + folderStates: Record, + checkedItems: Record, + users: Record + ): TreeDataItem[] => { const results = convertFileSystemEntryToTreeDataItem({ imports: recentResults.results.map((i) => ({ ...i, protocol: 'project://' })), folderStates, @@ -503,13 +941,13 @@ export const projectTreeLogic = kea([ s.users, ], ( - searchResults, - searchResultsLoading, - folderStates, - checkedItems, - sortMethod, - onlyFolders, - users + searchResults: SearchResults, + searchResultsLoading: boolean, + folderStates: Record, + checkedItems: Record, + sortMethod: ProjectTreeSortMethod, + onlyFolders: boolean, + users: Record ): TreeDataItem[] => { const results = convertFileSystemEntryToTreeDataItem({ imports: searchResults.results.map((i) => ({ ...i, protocol: 'project://' })), @@ -552,7 +990,14 @@ export const projectTreeLogic = kea([ ], projectTreeItems: [ (s) => [s.searchTerm, s.searchTreeItems, s.projectTree, s.loadingPaths, s.recentTreeItems, s.sortMethod], - (searchTerm, searchTreeItems, projectTree, loadingPaths, recentTreeItems, sortMethod): TreeDataItem[] => { + ( + searchTerm: string, + searchTreeItems: TreeDataItem[], + projectTree: TreeDataItem[], + loadingPaths: Record, + recentTreeItems: TreeDataItem[], + sortMethod: ProjectTreeSortMethod + ): TreeDataItem[] => { if (searchTerm) { return searchTreeItems } @@ -582,17 +1027,17 @@ export const projectTreeLogic = kea([ (_, props) => props.root, ], ( - searchTerm, - searchTreeItems, - searchResultsLoading, - projectTree, - loadingPaths, - recentTreeItems, - recentResultsLoading, - sortMethod, - onlyFolders, - getStaticTreeItems, - getCustomProductTreeItems, + searchTerm: string, + searchTreeItems: TreeDataItem[], + searchResultsLoading: boolean, + projectTree: TreeDataItem[], + loadingPaths: Record, + recentTreeItems: TreeDataItem[], + recentResultsLoading: boolean, + sortMethod: ProjectTreeSortMethod, + onlyFolders: boolean, + getStaticTreeItems: (searchTerm: string, onlyFolders: boolean) => TreeDataItem[], + getCustomProductTreeItems: (searchTerm: string) => TreeDataItem[], root ): TreeDataItem[] => { if (root === 'custom-products://') { @@ -630,7 +1075,7 @@ export const projectTreeLogic = kea([ (_, props) => props.includeRoot, (_, props) => props.hideFolders, ], - (fullFileSystem, searchTerm, root, includeRoot, hideFolders): TreeDataItem[] => { + (fullFileSystem: TreeDataItem[], searchTerm: string, root, includeRoot, hideFolders): TreeDataItem[] => { let firstFolders = fullFileSystem // Filter out folders specified in hideFolders prop @@ -710,15 +1155,16 @@ export const projectTreeLogic = kea([ ], treeTableColumnOffsets: [ (s) => [s.treeTableColumnSizes], - (sizes): number[] => sizes.map((_, index) => sizes.slice(0, index).reduce((acc, s) => acc + s, 0)), + (sizes: number[]): number[] => + sizes.map((_, index) => sizes.slice(0, index).reduce((acc, s) => acc + s, 0)), ], checkedItemCountNumeric: [ (s) => [s.checkedItems], - (checkedItems): number => Object.values(checkedItems).filter((v) => !!v).length, + (checkedItems: Record): number => Object.values(checkedItems).filter((v) => !!v).length, ], checkedItemsCount: [ (s) => [s.checkedItems, s.viableItemsById], - (checkedItems, viableItemsById): string => { + (checkedItems: Record, viableItemsById: Record): string => { let hasFolder = false let sum = 0 for (const [key, value] of Object.entries(checkedItems)) { @@ -735,7 +1181,10 @@ export const projectTreeLogic = kea([ ], checkedItemsArray: [ (s) => [s.checkedItems, s.viableItemsById], - (checkedItems, viableItemsById): FileSystemEntry[] => { + ( + checkedItems: Record, + viableItemsById: Record + ): FileSystemEntry[] => { return Object.entries(checkedItems) .filter(([_, checked]) => checked) .map(([id]) => viableItemsById[id]) diff --git a/frontend/src/layout/panel-layout/ai-first/tabs/editToolsLogic.ts b/frontend/src/layout/panel-layout/ai-first/tabs/editToolsLogic.ts index 31adbd03fed5..ce194dd65caf 100644 --- a/frontend/src/layout/panel-layout/ai-first/tabs/editToolsLogic.ts +++ b/frontend/src/layout/panel-layout/ai-first/tabs/editToolsLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers, selectors } from 'kea' import { lemonToast } from '@posthog/lemon-ui' @@ -8,10 +8,59 @@ import { customProductsLogic } from '~/layout/panel-layout/ProjectTree/customPro import { getItemId } from '~/layout/panel-layout/ProjectTree/utils' import { UserProductListItem, UserProductListReason } from '~/queries/schema/schema-general' -import type { editToolsLogicType } from './editToolsLogicType' - const PRODUCTS_ROOT = 'products://' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface editToolsLogicValues { + customProducts: UserProductListItem[] // customProductsLogic + checkedTools: Record + isEditMode: boolean + localToggles: Record + selectedPaths: Set +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface editToolsLogicActions { + loadCustomProducts: () => any // customProductsLogic + loadCustomProductsSuccess: ( + customProducts: UserProductListItem[], + payload?: any + ) => { + customProducts: UserProductListItem[] + payload?: any + } // customProductsLogic + enterEditMode: () => { + value: true + } + saveAndExitEditMode: () => { + value: true + } + setLocalToggles: (toggles: Record) => { + toggles: Record + } + toggleTool: (toolPath: string) => { + toolPath: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface editToolsLogicMeta { + __keaTypeGenInternalSelectorTypes: { + selectedPaths: (customProducts: UserProductListItem[]) => Set + checkedTools: ( + customProducts: UserProductListItem[], + localToggles: Record + ) => Record + } +} + +export type editToolsLogicType = MakeLogicType< + editToolsLogicValues, + editToolsLogicActions, + Record, + editToolsLogicMeta +> + export const editToolsLogic = kea([ path(['layout', 'panel-layout', 'ai-first', 'tabs', 'editToolsLogic']), connect(() => ({ @@ -43,12 +92,12 @@ export const editToolsLogic = kea([ selectors({ selectedPaths: [ (s) => [s.customProducts], - (customProducts): Set => + (customProducts: UserProductListItem[]): Set => new Set(customProducts.map((item: { product_path: string }) => item.product_path)), ], checkedTools: [ (s) => [s.customProducts, s.localToggles], - (customProducts, localToggles): Record => { + (customProducts: UserProductListItem[], localToggles: Record): Record => { const result: Record = {} for (const item of customProducts) { const id = getItemId({ path: item.product_path, type: '' }, PRODUCTS_ROOT) diff --git a/frontend/src/layout/panel-layout/ai-first/tabs/navRecentsLogic.ts b/frontend/src/layout/panel-layout/ai-first/tabs/navRecentsLogic.ts index 13aec3d5b039..2600ef3b6734 100644 --- a/frontend/src/layout/panel-layout/ai-first/tabs/navRecentsLogic.ts +++ b/frontend/src/layout/panel-layout/ai-first/tabs/navRecentsLogic.ts @@ -1,12 +1,28 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { recentItemsModel } from '~/models/recentItemsModel' import { FileSystemEntry } from '~/queries/schema/schema-general' -import type { navRecentsLogicType } from './navRecentsLogicType' - const NAV_RECENTS_LIMIT = 15 +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navRecentsLogicValues { + cachedRecents: FileSystemEntry[] // recentItemsModel + recentsHasLoaded: boolean // recentItemsModel + recentItems: FileSystemEntry[] + recentItemsLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navRecentsLogicMeta { + __keaTypeGenInternalSelectorTypes: { + recentItems: (cachedRecents: FileSystemEntry[]) => FileSystemEntry[] + recentItemsLoading: (recentsHasLoaded: boolean) => boolean + } +} + +export type navRecentsLogicType = MakeLogicType, navRecentsLogicMeta> + export const navRecentsLogic = kea([ path(['layout', 'panel-layout', 'ai-first', 'tabs', 'navRecentsLogic']), connect(() => ({ @@ -15,8 +31,8 @@ export const navRecentsLogic = kea([ selectors({ recentItems: [ (s) => [s.cachedRecents], - (cachedRecents): FileSystemEntry[] => cachedRecents.slice(0, NAV_RECENTS_LIMIT), + (cachedRecents: FileSystemEntry[]): FileSystemEntry[] => cachedRecents.slice(0, NAV_RECENTS_LIMIT), ], - recentItemsLoading: [(s) => [s.recentsHasLoaded], (recentsHasLoaded): boolean => !recentsHasLoaded], + recentItemsLoading: [(s) => [s.recentsHasLoaded], (recentsHasLoaded: boolean): boolean => !recentsHasLoaded], }), ]) diff --git a/frontend/src/layout/panel-layout/installationStatusNavLogic.ts b/frontend/src/layout/panel-layout/installationStatusNavLogic.ts index 2e4a568c2f97..8989b146744b 100644 --- a/frontend/src/layout/panel-layout/installationStatusNavLogic.ts +++ b/frontend/src/layout/panel-layout/installationStatusNavLogic.ts @@ -1,4 +1,4 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { activeCloudRunLogic } from 'scenes/onboarding/shared/wizard-sync/activeCloudRunLogic' import { wizardActiveSessionDetectorLogic } from 'scenes/onboarding/shared/wizard-sync/wizardActiveSessionDetectorLogic' @@ -6,10 +6,54 @@ import { wizardSyncUiLogic } from 'scenes/onboarding/shared/wizard-sync/wizardSy import { teamLogic } from 'scenes/teamLogic' import { urls } from 'scenes/urls' -import type { installationStatusNavLogicType } from './installationStatusNavLogicType' +import type { CloudRunHandle } from '../../scenes/onboarding/shared/wizard-sync/activeCloudRunLogic' +import type { TeamPublicType, TeamType } from '../../types' export type NavInstallationPhase = 'running' | 'completed' | 'error' | 'connecting' | 'idle' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface installationStatusNavLogicValues { + activeCloudRun: CloudRunHandle | null // activeCloudRunLogic + panelMounted: boolean // activeCloudRunLogic + currentTeam: TeamPublicType | TeamType | null // teamLogic + hasOnboardedAnyProduct: boolean // teamLogic + hasActiveSession: boolean // wizardActiveSessionDetectorLogic + dialogOpen: boolean // wizardSyncUiLogic + isRunActive: boolean + onboardingUrl: string + phase: NavInstallationPhase + shouldShow: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface installationStatusNavLogicActions { + openDialog: () => { + value: true + } // wizardSyncUiLogic +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface installationStatusNavLogicMeta { + __keaTypeGenInternalSelectorTypes: { + shouldShow: ( + hasOnboardedAnyProduct: boolean, + currentTeam: TeamPublicType | TeamType | null, + activeCloudRun: CloudRunHandle | null, + hasActiveSession: boolean, + panelMounted: boolean + ) => boolean + isRunActive: (activeCloudRun: CloudRunHandle | null, hasActiveSession: boolean) => boolean + phase: (isRunActive: boolean) => NavInstallationPhase + } +} + +export type installationStatusNavLogicType = MakeLogicType< + installationStatusNavLogicValues, + installationStatusNavLogicActions, + Record, + installationStatusNavLogicMeta +> + /** * Coordinates whether to show an "Installation status" item in the sidebar footer, * and what label / badge tone to display. @@ -39,7 +83,15 @@ export const installationStatusNavLogic = kea([ /** Whether the nav item should render at all. */ shouldShow: [ (s) => [s.hasOnboardedAnyProduct, s.currentTeam, s.activeCloudRun, s.hasActiveSession, s.panelMounted], - (hasOnboardedAnyProduct, currentTeam, activeCloudRun, hasActiveSession, panelMounted): boolean => { + ( + hasOnboardedAnyProduct: boolean, + currentTeam: null | import('../../types').TeamPublicType | import('../../types').TeamType, + activeCloudRun: + | null + | import('scenes/onboarding/shared/wizard-sync/activeCloudRunLogic').CloudRunHandle, + hasActiveSession: boolean, + panelMounted: boolean + ): boolean => { // Panel-mounted inline progress already shows the run — avoid double-surfacing if (panelMounted) { return false @@ -59,11 +111,19 @@ export const installationStatusNavLogic = kea([ /** Whether an active run (cloud or local) is the reason we're showing. */ isRunActive: [ (s) => [s.activeCloudRun, s.hasActiveSession], - (activeCloudRun, hasActiveSession): boolean => !!(activeCloudRun || hasActiveSession), + ( + activeCloudRun: + | null + | import('scenes/onboarding/shared/wizard-sync/activeCloudRunLogic').CloudRunHandle, + hasActiveSession: boolean + ): boolean => !!(activeCloudRun || hasActiveSession), ], /** High-level phase for the badge tone: 'running' while in flight, 'idle' for incomplete onboarding. */ - phase: [(s) => [s.isRunActive], (isRunActive): NavInstallationPhase => (isRunActive ? 'running' : 'idle')], + phase: [ + (s) => [s.isRunActive], + (isRunActive: boolean): NavInstallationPhase => (isRunActive ? 'running' : 'idle'), + ], /** URL to navigate to on click when no run is active. */ onboardingUrl: [() => [], (): string => urls.onboarding()], diff --git a/frontend/src/layout/panel-layout/panelLayoutLogic.tsx b/frontend/src/layout/panel-layout/panelLayoutLogic.tsx index efa017eee712..fc483beeff0a 100644 --- a/frontend/src/layout/panel-layout/panelLayoutLogic.tsx +++ b/frontend/src/layout/panel-layout/panelLayoutLogic.tsx @@ -1,10 +1,9 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { router, urlToAction } from 'kea-router' import { removeProjectIdIfPresent } from 'lib/utils/kea-router' import { navigation3000Logic } from '../navigation-3000/navigationLogic' -import type { panelLayoutLogicType } from './panelLayoutLogicType' export type PanelLayoutNavIdentifier = | 'Project' @@ -26,6 +25,119 @@ export const PANEL_NAVBAR_DEFAULT_WIDTH: number = 215 // Below this the drag snaps to collapsed mode. export const PANEL_NAVBAR_COLLAPSE_THRESHOLD: number = 140 +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface panelLayoutLogicValues { + mobileLayout: boolean // navigation3000Logic + location: { + pathname: string + search: string + hash: string + } // router + activePanelIdentifier: string + activePanelIdentifierFromUrl: PanelLayoutNavIdentifier | '' + activePanelIdentifierFromUrlAiFirst: PanelLayoutNavIdentifier | '' + expandedNavSections: Record + isLayoutNavCollapsed: boolean + isLayoutNavCollapsedDesktop: boolean + isLayoutNavbarVisible: boolean + isLayoutNavbarVisibleForDesktop: boolean + isLayoutNavbarVisibleForMobile: boolean + isLayoutPanelCloseable: boolean + isLayoutPanelVisible: boolean + mainContentRect: DOMRect | null + mainContentRef: PanelLayoutMainContentRef + navExperimentActiveTab: NavExperimentTab + navbarWidth: number + panelIsResizing: boolean + panelWidth: number + panelWillHide: boolean + pathname: string + sidePanelWidth: number + visibleSideAction: string + visitedNavTabs: NavExperimentTab[] + visitedPanels: PanelLayoutNavIdentifier[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface panelLayoutLogicActions { + clearActivePanelIdentifier: () => { + value: true + } + closePanel: () => { + value: true + } + resetPanelLayout: (keyboardAction: boolean) => { + keyboardAction: boolean + } + setActivePanelIdentifier: (identifier: PanelLayoutNavIdentifier) => { + identifier: PanelLayoutNavIdentifier + } + setMainContentRect: (rect: DOMRect) => { + rect: DOMRect + } + setMainContentRef: (ref: PanelLayoutMainContentRef) => { + ref: PanelLayoutMainContentRef + } + setNavExperimentTab: (tab: NavExperimentTab) => { + tab: NavExperimentTab + } + setNavbarWidth: (width: number) => { + width: number + } + setPanelIsResizing: (isResizing: boolean) => { + isResizing: boolean + } + setPanelWidth: (width: number) => { + width: number + } + setPanelWillHide: (willHide: boolean) => { + willHide: boolean + } + setSidePanelWidth: (width: number) => { + width: number + } + setVisibleSideAction: (sideAction: string) => { + sideAction: string + } + showLayoutNavBar: (visible: boolean) => { + visible: boolean + } + showLayoutPanel: (visible: boolean) => { + visible: boolean + } + toggleLayoutNavCollapsed: (override?: boolean) => { + override: boolean | undefined + } + toggleNavSection: (section: string) => { + section: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface panelLayoutLogicMeta { + __keaTypeGenInternalSelectorTypes: { + isLayoutNavCollapsed: (isLayoutNavCollapsedDesktop: boolean, mobileLayout: boolean) => boolean + activePanelIdentifierFromUrl: (location: { + hash: string + pathname: string + search: string + }) => PanelLayoutNavIdentifier | '' + activePanelIdentifierFromUrlAiFirst: (location: { + hash: string + pathname: string + search: string + }) => PanelLayoutNavIdentifier | '' + pathname: (location: { hash: string; pathname: string; search: string }) => string + } +} + +export type panelLayoutLogicType = MakeLogicType< + panelLayoutLogicValues, + panelLayoutLogicActions, + Record, + panelLayoutLogicMeta +> + export const panelLayoutLogic = kea([ path(['layout', 'panel-layout', 'panelLayoutLogic']), connect(() => ({ @@ -246,11 +358,12 @@ export const panelLayoutLogic = kea([ selectors({ isLayoutNavCollapsed: [ (s) => [s.isLayoutNavCollapsedDesktop, s.mobileLayout], - (isLayoutNavCollapsedDesktop, mobileLayout): boolean => !mobileLayout && isLayoutNavCollapsedDesktop, + (isLayoutNavCollapsedDesktop: boolean, mobileLayout: boolean): boolean => + !mobileLayout && isLayoutNavCollapsedDesktop, ], activePanelIdentifierFromUrl: [ () => [router.selectors.location], - (location): PanelLayoutNavIdentifier | '' => { + (location: { hash: string; pathname: string; search: string }): PanelLayoutNavIdentifier | '' => { const cleanPath = removeProjectIdIfPresent(location.pathname) if (cleanPath.startsWith('/data-management/')) { @@ -266,7 +379,7 @@ export const panelLayoutLogic = kea([ ], activePanelIdentifierFromUrlAiFirst: [ () => [router.selectors.location], - (location): PanelLayoutNavIdentifier | '' => { + (location: { hash: string; pathname: string; search: string }): PanelLayoutNavIdentifier | '' => { const cleanPath = removeProjectIdIfPresent(location.pathname) if ( @@ -281,7 +394,10 @@ export const panelLayoutLogic = kea([ return '' }, ], - pathname: [(s) => [s.location], (location): string => location.pathname], + pathname: [ + (s) => [s.location], + (location: { hash: string; pathname: string; search: string }): string => location.pathname, + ], }), urlToAction(({ actions, values }) => ({ '*': () => { diff --git a/frontend/src/layout/scenes/sceneLayoutLogic.tsx b/frontend/src/layout/scenes/sceneLayoutLogic.tsx index 63b059388739..5e9cd5e98997 100644 --- a/frontend/src/layout/scenes/sceneLayoutLogic.tsx +++ b/frontend/src/layout/scenes/sceneLayoutLogic.tsx @@ -1,14 +1,46 @@ -import { actions, connect, kea, listeners, path, reducers } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers } from 'kea' import React from 'react' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' import { SceneConfig } from 'scenes/sceneTypes' +import type { FeatureFlagsSet } from '../../lib/logic/featureFlagLogic' import { panelLayoutLogic } from '../panel-layout/panelLayoutLogic' -import type { sceneLayoutLogicType } from './sceneLayoutLogicType' export type SceneLayoutContainerRef = React.RefObject | null +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sceneLayoutLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + mainContentRect: DOMRect | null // panelLayoutLogic + sceneLayoutConfig: SceneConfig | null + scenePanelElement: HTMLElement | null + scenePanelIsPresent: boolean + scenePanelOpenManual: boolean + showDescription: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sceneLayoutLogicActions { + registerScenePanelElement: (element: HTMLElement | null) => { + element: HTMLElement | null + } + setSceneLayoutConfig: (config: SceneConfig) => { + config: SceneConfig + } + setScenePanelIsPresent: (active: boolean) => { + active: boolean + } + setScenePanelOpen: (open: boolean) => { + open: boolean + } + toggleShowDescription: () => { + value: true + } +} + +export type sceneLayoutLogicType = MakeLogicType + export const sceneLayoutLogic = kea([ path(['layout', 'scene-layout', 'sceneLayoutLogic']), connect(() => ({ diff --git a/frontend/src/lib/approvals/approvalsGateLogic.ts b/frontend/src/lib/approvals/approvalsGateLogic.ts index e1190381ebff..b43dd335f82b 100644 --- a/frontend/src/lib/approvals/approvalsGateLogic.ts +++ b/frontend/src/lib/approvals/approvalsGateLogic.ts @@ -1,4 +1,4 @@ -import { afterMount, connect, kea, path, selectors } from 'kea' +import { MakeLogicType, afterMount, connect, kea, path, selectors } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' @@ -7,7 +7,54 @@ import { userLogic } from 'scenes/userLogic' import { ApprovalPolicy, AvailableFeature } from '~/types' -import type { approvalsGateLogicType } from './approvalsGateLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface approvalsGateLogicValues { + currentTeamIdStrict: number | string // teamLogic + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean // userLogic + activePolicies: ApprovalPolicy[] + activePoliciesLoading: boolean + isApprovalRequired: (actionKey: string) => boolean + isApprovalsFeatureEnabled: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface approvalsGateLogicActions { + loadActivePolicies: () => any + loadActivePoliciesFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadActivePoliciesSuccess: ( + activePolicies: ApprovalPolicy[], + payload?: any + ) => { + activePolicies: ApprovalPolicy[] + payload?: any + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface approvalsGateLogicMeta { + __keaTypeGenInternalSelectorTypes: { + isApprovalsFeatureEnabled: ( + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean + ) => boolean + isApprovalRequired: ( + isApprovalsFeatureEnabled: boolean, + activePolicies: ApprovalPolicy[] + ) => (actionKey: string) => boolean + } +} + +export type approvalsGateLogicType = MakeLogicType< + approvalsGateLogicValues, + approvalsGateLogicActions, + Record, + approvalsGateLogicMeta +> export const approvalsGateLogic = kea([ path(['lib', 'approvals', 'approvalsGateLogic']), @@ -41,7 +88,8 @@ export const approvalsGateLogic = kea([ selectors({ isApprovalsFeatureEnabled: [ (s) => [s.hasAvailableFeature], - (hasAvailableFeature): boolean => hasAvailableFeature(AvailableFeature.APPROVALS), + (hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean): boolean => + hasAvailableFeature(AvailableFeature.APPROVALS), ], isApprovalRequired: [ diff --git a/frontend/src/lib/components/Account/newAccountMenuLogic.ts b/frontend/src/lib/components/Account/newAccountMenuLogic.ts index d8bd4e2cc055..e96402ddf925 100644 --- a/frontend/src/lib/components/Account/newAccountMenuLogic.ts +++ b/frontend/src/lib/components/Account/newAccountMenuLogic.ts @@ -1,6 +1,41 @@ -import { actions, kea, path, reducers } from 'kea' +import { MakeLogicType, actions, kea, path, reducers } from 'kea' -import type { newAccountMenuLogicType } from './newAccountMenuLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface newAccountMenuLogicValues { + isAccountMenuOpen: boolean + isOrgSwitcherOpen: boolean + isProjectSwitcherOpen: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface newAccountMenuLogicActions { + closeOrgSwitcher: () => { + value: true + } + closeProjectSwitcher: () => { + value: true + } + openOrgSwitcher: () => { + value: true + } + openProjectSwitcher: () => { + value: true + } + setAccountMenuOpen: (isOpen: boolean) => { + isOpen: boolean + } + toggleAccountMenu: () => { + value: true + } + toggleOrgSwitcher: () => { + value: true + } + toggleProjectSwitcher: () => { + value: true + } +} + +export type newAccountMenuLogicType = MakeLogicType export const newAccountMenuLogic = kea([ path(['lib', 'components', 'Account', 'accountMenuLogic']), diff --git a/frontend/src/lib/components/Account/pendingInvitesLogic.ts b/frontend/src/lib/components/Account/pendingInvitesLogic.ts index 487d9ef059b6..77b7b8d6203a 100644 --- a/frontend/src/lib/components/Account/pendingInvitesLogic.ts +++ b/frontend/src/lib/components/Account/pendingInvitesLogic.ts @@ -1,19 +1,42 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { userLogic } from 'scenes/userLogic' import { PendingInviteForCurrentUser } from '~/types' -import type { pendingInvitesLogicType } from './pendingInvitesLogicType' +import type { UserType } from '../../../types' export type { PendingInviteForCurrentUser } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface pendingInvitesLogicValues { + user: UserType | null // userLogic + pendingInvites: PendingInviteForCurrentUser[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface pendingInvitesLogicMeta { + __keaTypeGenInternalSelectorTypes: { + pendingInvites: (user: UserType | null) => PendingInviteForCurrentUser[] + } +} + +export type pendingInvitesLogicType = MakeLogicType< + pendingInvitesLogicValues, + {}, + Record, + pendingInvitesLogicMeta +> + export const pendingInvitesLogic = kea([ path(['lib', 'components', 'Account', 'pendingInvitesLogic']), connect(() => ({ values: [userLogic, ['user']], })), selectors({ - pendingInvites: [(s) => [s.user], (user): PendingInviteForCurrentUser[] => user?.pending_invites ?? []], + pendingInvites: [ + (s) => [s.user], + (user: null | import('~/types').UserType): PendingInviteForCurrentUser[] => user?.pending_invites ?? [], + ], }), ]) diff --git a/frontend/src/lib/components/ActivityLog/activityLogLogic.tsx b/frontend/src/lib/components/ActivityLog/activityLogLogic.tsx index 83bd8f521705..303eb58bdc72 100644 --- a/frontend/src/lib/components/ActivityLog/activityLogLogic.tsx +++ b/frontend/src/lib/components/ActivityLog/activityLogLogic.tsx @@ -1,4 +1,4 @@ -import { actions, events, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, events, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { router, urlToAction } from 'kea-router' @@ -16,8 +16,6 @@ import { urls } from 'scenes/urls' import { ActivityScope } from '~/types' -import type { activityLogLogicType } from './activityLogLogicType' - // Define which scopes should be expanded to include multiple scopes const SCOPE_EXPANSIONS: Partial> = { [ActivityScope.TAG]: [ActivityScope.TAG, ActivityScope.TAGGED_ITEM], @@ -115,6 +113,65 @@ export type ActivityLogLogicProps = { startingPage?: number } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface activityLogLogicValues { + activity: ActivityLogPaginatedResponse + activityLoading: boolean + highlightedActivityId: string | null + humanizedActivity: HumanizedActivityLogItem[] + page: number + pagination: PaginationManual + totalCount: number | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface activityLogLogicActions { + fetchActivity: () => any + fetchActivityFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + fetchActivitySuccess: ( + activity: { + count: any + results: ActivityLogItem[] + }, + payload?: any + ) => { + activity: { + count: any + results: ActivityLogItem[] + } + payload?: any + } + setHighlightedActivityId: (id: string | null) => { + id: string | null + } + setPage: (page: number) => { + page: number + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface activityLogLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + pagination: (page: number, totalCount: number | null) => PaginationManual + humanizedActivity: (activity: ActivityLogPaginatedResponse) => HumanizedActivityLogItem[] + totalCount: (activity: ActivityLogPaginatedResponse) => number | null + } +} + +export type activityLogLogicType = MakeLogicType< + activityLogLogicValues, + activityLogLogicActions, + ActivityLogLogicProps, + activityLogLogicMeta +> + export const activityLogLogic = kea([ props({} as ActivityLogLogicProps), key(({ scope, id }) => `activity/${Array.isArray(scope) ? scope.join(',') : scope}/${id || 'all'}`), @@ -155,7 +212,7 @@ export const activityLogLogic = kea([ selectors(({ actions }) => ({ pagination: [ (s) => [s.page, s.totalCount], - (page, totalCount): PaginationManual => { + (page: number, totalCount: number | null): PaginationManual => { return { controlled: true, pageSize: ACTIVITY_PAGE_SIZE, @@ -168,13 +225,13 @@ export const activityLogLogic = kea([ ], humanizedActivity: [ (s) => [s.activity], - (activity): HumanizedActivityLogItem[] => { + (activity: ActivityLogPaginatedResponse): HumanizedActivityLogItem[] => { return activity.results ? humanize(activity.results, describerFor) : [] }, ], totalCount: [ (s) => [s.activity], - (activity): number | null => { + (activity: ActivityLogPaginatedResponse): number | null => { return activity.count ?? null }, ], diff --git a/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts b/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts index ecf9ae5f894f..e344fb26ea80 100644 --- a/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts +++ b/frontend/src/lib/components/AddToDashboard/addToDashboardModalLogic.ts @@ -1,5 +1,5 @@ import FuseClass, { FuseResult } from 'fuse.js' -import { actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { router } from 'kea-router' import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast' @@ -14,11 +14,139 @@ import { userLogic } from 'scenes/userLogic' import { dashboardsModel, nameCompareFunction } from '~/models/dashboardsModel' import { DashboardBasicType, DashboardType, InsightLogicProps } from '~/types' -import type { addToDashboardModalLogicType } from './addToDashboardModalLogicType' +import type { Node } from '../../../queries/schema/schema-general' +import type { QueryBasedInsightModel, UserType } from '../../../types' // Helping kea-typegen navigate the exported default class for Fuse export interface Fuse extends FuseClass {} +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface addToDashboardModalLogicValues { + insight: Partial>>> // insightLogic + user: UserType | null // userLogic + _dashboardToNavigateTo: number | null + availableDashboards: DashboardBasicType[] + currentDashboards: DashboardBasicType[] + dashboardWithActiveAPICall: number | null + dashboardsFuse: Fuse + filteredDashboards: DashboardBasicType[] + orderedDashboards: DashboardBasicType[] + scrollIndex: number + searchQuery: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface addToDashboardModalLogicActions { + reportCreatedDashboardFromModal: () => { + value: true + } // eventUsageLogic + reportRemovedInsightFromDashboard: ( + insight: Partial>>> | null, + dashboardId: number | null + ) => { + dashboardId: number | null + insight: Partial>>> | null + } // eventUsageLogic + reportSavedInsightToDashboard: ( + insight: Partial>>> | null, + dashboardId: number | null + ) => { + dashboardId: number | null + insight: Partial>>> | null + } // eventUsageLogic + updateInsight: ( + insightUpdate: Partial>>>, + callback?: (() => void) | undefined + ) => { + callback: (() => void) | undefined + insightUpdate: Partial>>> + } // insightLogic + updateInsightFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } // insightLogic + updateInsightSuccess: ( + insight: Partial>>>, + payload?: + | { + callback: (() => void) | undefined + insightUpdate: Partial>>> + } + | undefined + ) => { + insight: Partial>>> + payload?: { + callback: (() => void) | undefined + insightUpdate: Partial>>> + } + } // insightLogic + showNewDashboardModal: () => { + value: true + } // newDashboardLogic + addNewDashboard: () => { + value: true + } + addToDashboard: (dashboardId: number) => { + dashboardId: number + } + removeFromDashboard: (dashboardId: number) => { + dashboardId: number + } + setDashboardToNavigateTo: (dashboardId: number | null) => { + dashboardId: number | null + } + setScrollIndex: (index: number) => { + index: number + } + setSearchQuery: (query: string) => { + query: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface addToDashboardModalLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + dashboardsFuse: ( + nameSortedDashboards: ( + | DashboardBasicType + | DashboardType>>> + )[] + ) => Fuse + filteredDashboards: ( + searchQuery: string, + dashboardsFuse: Fuse, + nameSortedDashboards: ( + | DashboardBasicType + | DashboardType>>> + )[] + ) => DashboardBasicType[] + currentDashboards: ( + filteredDashboards: DashboardBasicType[], + insight: Partial>>> + ) => DashboardBasicType[] + availableDashboards: ( + filteredDashboards: DashboardBasicType[], + currentDashboards: DashboardBasicType[] + ) => DashboardBasicType[] + orderedDashboards: ( + currentDashboards: DashboardBasicType[], + availableDashboards: DashboardBasicType[], + user: UserType | null + ) => DashboardBasicType[] + } +} + +export type addToDashboardModalLogicType = MakeLogicType< + addToDashboardModalLogicValues, + addToDashboardModalLogicActions, + InsightLogicProps, + addToDashboardModalLogicMeta +> + export const addToDashboardModalLogic = kea([ props({} as InsightLogicProps), key(keyForInsightLogicProps('new')), @@ -64,7 +192,16 @@ export const addToDashboardModalLogic = kea([ selectors({ dashboardsFuse: [ () => [dashboardsModel.selectors.nameSortedDashboards], - (nameSortedDashboards): Fuse => { + ( + nameSortedDashboards: ( + | DashboardBasicType + | DashboardType< + import('~/types').QueryBasedInsightModel< + import('../../../queries/schema').Node> + > + > + )[] + ): Fuse => { return createFuse(nameSortedDashboards || [], { keys: ['name', 'description', 'tags'], }) @@ -72,24 +209,46 @@ export const addToDashboardModalLogic = kea([ ], filteredDashboards: [ (s) => [s.searchQuery, s.dashboardsFuse, dashboardsModel.selectors.nameSortedDashboards], - (searchQuery, dashboardsFuse, nameSortedDashboards): DashboardBasicType[] => + ( + searchQuery: string, + dashboardsFuse: Fuse, + nameSortedDashboards: ( + | DashboardBasicType + | DashboardType< + import('~/types').QueryBasedInsightModel< + import('../../../queries/schema').Node> + > + > + )[] + ): DashboardBasicType[] => searchQuery.length ? dashboardsFuse.search(searchQuery).map((r: FuseResult) => r.item) : nameSortedDashboards, ], currentDashboards: [ (s) => [s.filteredDashboards, s.insight], - (filteredDashboards, insight): DashboardBasicType[] => + ( + filteredDashboards: DashboardBasicType[], + insight: Partial< + import('~/types').QueryBasedInsightModel< + import('../../../queries/schema').Node> + > + > + ): DashboardBasicType[] => filteredDashboards.filter((d) => insight.dashboard_tiles?.map((dt) => dt.dashboard_id)?.includes(d.id)), ], availableDashboards: [ (s) => [s.filteredDashboards, s.currentDashboards], - (filteredDashboards, currentDashboards): DashboardBasicType[] => + (filteredDashboards: DashboardBasicType[], currentDashboards: DashboardBasicType[]): DashboardBasicType[] => filteredDashboards.filter((d) => !currentDashboards?.map((cd) => cd.id).includes(d.id)), ], orderedDashboards: [ (s) => [s.currentDashboards, s.availableDashboards, userLogic.selectors.user], - (currentDashboards, availableDashboards, user): DashboardBasicType[] => { + ( + currentDashboards: DashboardBasicType[], + availableDashboards: DashboardBasicType[], + user: null | import('~/types').UserType + ): DashboardBasicType[] => { const myUuid = user?.uuid ?? null const currentSorted = [...currentDashboards].sort(nameCompareFunction) const isMine = (d: DashboardBasicType): boolean => myUuid !== null && d.created_by?.uuid === myUuid diff --git a/frontend/src/lib/components/AnnotationsOverlay/annotationsOverlayLogic.ts b/frontend/src/lib/components/AnnotationsOverlay/annotationsOverlayLogic.ts index d4082ec4adc5..03a79c701cfc 100644 --- a/frontend/src/lib/components/AnnotationsOverlay/annotationsOverlayLogic.ts +++ b/frontend/src/lib/components/AnnotationsOverlay/annotationsOverlayLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { isPersonPropertyFilter, parseProperties } from 'lib/components/PropertyFilters/utils' import { FEATURE_FLAGS } from 'lib/constants' @@ -24,7 +24,10 @@ import { QueryBasedInsightModel, } from '~/types' -import type { annotationsOverlayLogicType } from './annotationsOverlayLogicType' +import type { AnnotationData } from '../../../models/annotationsModel' +import type { Node } from '../../../queries/schema/schema-general' +import type { RawAnnotationType } from '../../../types' +import type { FeatureFlagsSet } from '../../logic/featureFlagLogic' export interface AnnotationsOverlayLogicProps extends Omit { dashboardId: DashboardType['id'] | undefined @@ -72,6 +75,117 @@ function hasPersonPropertyFiltersOrBreakdown( return false } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface annotationsOverlayLogicValues { + annotations: AnnotationType[] // annotationsModel + annotationsLoading: boolean // annotationsModel + featureFlags: FeatureFlagsSet // featureFlagLogic + insightId: number | null // insightLogic + savedInsight: Partial>>> // insightLogic + breakdownFilter: BreakdownFilter | null | undefined // insightVizDataLogic + interval: IntervalType | null | undefined // insightVizDataLogic + properties: PropertyGroupFilter | AnyPropertyFilter[] | null | undefined // insightVizDataLogic + timezone: string // teamLogic + activeDate: Dayjs | null + annotationBadgeDataIndices: Array<{ + dataIndex: number + date: Dayjs + dateKey: string + }> + annotationsOverlayProps: AnnotationsOverlayLogicProps + dateRange: [Dayjs, Dayjs] | null + groupedAnnotations: Record + groupingUnit: IntervalType + intervalUnit: IntervalType + isDateLocked: boolean + isPopoverShown: boolean + relevantAnnotations: DatedAnnotationType[] + tickDates: Dayjs[] + tickPositions: number[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface annotationsOverlayLogicActions { + createAnnotationGenerically: (annotationData: AnnotationData) => AnnotationData // annotationsModel + deleteAnnotation: (annotation: AnnotationType) => { + annotation: AnnotationType + } // annotationsModel + updateAnnotation: (args_0: { + annotationData: AnnotationDataWithoutInsight + annotationId: RawAnnotationType['id'] + }) => { + annotationData: AnnotationDataWithoutInsight + annotationId: RawAnnotationType[] + } // annotationsModel + activateDate: (date: Dayjs) => { + date: Dayjs + } + closePopover: () => { + value: true + } + createAnnotation: (annotationData: AnnotationDataWithoutInsight) => { + annotationData: AnnotationDataWithoutInsight + } + deactivateDate: () => { + value: true + } + lockDate: () => { + value: true + } + unlockDate: () => { + value: true + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface annotationsOverlayLogicMeta { + key: number | string + __keaTypeGenInternalSelectorTypes: { + annotationsOverlayProps: (arg: any) => AnnotationsOverlayLogicProps + intervalUnit: (interval: IntervalType | null | undefined) => IntervalType + groupingUnit: (intervalUnit: IntervalType) => IntervalType + tickPositions: ( + ticks: { + value: number + }[] + ) => number[] + tickDates: (timezone: string, arg: string[], tickPositions: number[]) => Dayjs[] + dateRange: (timezone: string, arg: string[], intervalUnit: IntervalType) => [Dayjs, Dayjs] | null + relevantAnnotations: ( + annotations: AnnotationType[], + dateRange: [Dayjs, Dayjs] | null, + timezone: string, + featureFlags: FeatureFlagsSet, + insightNumericId: number | 'new', + dashboardId: number | undefined, + savedInsight: Partial>>>, + properties: PropertyGroupFilter | AnyPropertyFilter[] | null | undefined, + breakdownFilter: BreakdownFilter | null | undefined + ) => DatedAnnotationType[] + groupedAnnotations: ( + relevantAnnotations: DatedAnnotationType[], + intervalUnit: IntervalType + ) => Record + annotationBadgeDataIndices: ( + groupedAnnotations: Record, + intervalUnit: IntervalType, + timezone: string, + arg: string[] + ) => Array<{ + dataIndex: number + date: Dayjs + dateKey: string + }> + } +} + +export type annotationsOverlayLogicType = MakeLogicType< + annotationsOverlayLogicValues, + annotationsOverlayLogicActions, + AnnotationsOverlayLogicProps, + annotationsOverlayLogicMeta +> + export const annotationsOverlayLogic = kea([ path((key) => ['lib', 'components', 'Annotations', 'annotationsOverlayLogic', key]), props({ dashboardId: undefined } as AnnotationsOverlayLogicProps), @@ -136,17 +250,27 @@ export const annotationsOverlayLogic = kea([ () => [(_, props) => props], (props: AnnotationsOverlayLogicProps): AnnotationsOverlayLogicProps => props, ], - intervalUnit: [(s) => [s.interval], (interval) => interval || 'day'], - groupingUnit: [(s) => [s.intervalUnit], (intervalUnit): IntervalType => getGroupingUnit(intervalUnit)], - tickPositions: [(_, p) => [p.ticks], (ticks): number[] => ticks.map(({ value }) => value)], + intervalUnit: [(s) => [s.interval], (interval: IntervalType | null | undefined) => interval || 'day'], + groupingUnit: [ + (s) => [s.intervalUnit], + (intervalUnit: IntervalType): IntervalType => getGroupingUnit(intervalUnit), + ], + tickPositions: [ + (_, p) => [p.ticks], + ( + ticks: { + value: number + }[] + ): number[] => ticks.map(({ value }) => value), + ], tickDates: [ (s) => [s.timezone, (_, props: AnnotationsOverlayLogicProps) => props.dates, s.tickPositions], - (timezone, dates, tickPositions): Dayjs[] => + (timezone: string, dates: string[], tickPositions: number[]): Dayjs[] => tickPositions.map((dateIndex) => parseDateInTimezone(dates[dateIndex], timezone)), ], dateRange: [ (s) => [s.timezone, (_, props: AnnotationsOverlayLogicProps) => props.dates, s.intervalUnit], - (timezone, dates, intervalUnit): [Dayjs, Dayjs] | null => { + (timezone: string, dates: string[], intervalUnit: IntervalType): [Dayjs, Dayjs] | null => { if (dates.length === 0) { return null } @@ -168,15 +292,17 @@ export const annotationsOverlayLogic = kea([ s.breakdownFilter, ], ( - annotations, - dateRange, - timezone, - featureFlags, - insightNumericId, - dashboardId, - savedInsight, - properties, - breakdownFilter + annotations: AnnotationType[], + dateRange: [Dayjs, Dayjs] | null, + timezone: string, + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + insightNumericId: number | 'new', + dashboardId: number | undefined, + savedInsight: Partial< + QueryBasedInsightModel>> + >, + properties: PropertyGroupFilter | AnyPropertyFilter[] | null | undefined, + breakdownFilter: BreakdownFilter | null | undefined ) => { // This assumes that there are no more annotations in the project than AnnotationsViewSet // pagination class's default_limit of 100. As of June 2023, this is not true on Cloud US, @@ -243,7 +369,7 @@ export const annotationsOverlayLogic = kea([ ], groupedAnnotations: [ (s) => [s.relevantAnnotations, s.intervalUnit], - (relevantAnnotations, intervalUnit) => { + (relevantAnnotations: DatedAnnotationType[], intervalUnit: IntervalType) => { return groupBy(relevantAnnotations, (annotation) => { return determineAnnotationsDateGroup(annotation.date_marker, intervalUnit) }) @@ -259,10 +385,10 @@ export const annotationsOverlayLogic = kea([ (_, props: AnnotationsOverlayLogicProps) => props.dates, ], ( - groupedAnnotations, - intervalUnit, - timezone, - dates + groupedAnnotations: Record, + intervalUnit: IntervalType, + timezone: string, + dates: string[] ): Array<{ dateKey: string; date: Dayjs; dataIndex: number }> => { if (dates.length === 0) { return [] diff --git a/frontend/src/lib/components/AppMetrics/appMetricsLogic.ts b/frontend/src/lib/components/AppMetrics/appMetricsLogic.ts index 35b26890f76b..01c9b67baae4 100644 --- a/frontend/src/lib/components/AppMetrics/appMetricsLogic.ts +++ b/frontend/src/lib/components/AppMetrics/appMetricsLogic.ts @@ -1,4 +1,17 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, propsChanged, reducers, selectors } from 'kea' +import { + MakeLogicType, + actions, + afterMount, + connect, + kea, + key, + listeners, + path, + props, + propsChanged, + reducers, + selectors, +} from 'kea' import { loaders } from 'kea-loaders' import { subscriptions } from 'kea-subscriptions' @@ -10,7 +23,7 @@ import { teamLogic } from 'scenes/teamLogic' import { HogQLQueryString, hogql } from '~/queries/utils' -import type { appMetricsLogicType } from './appMetricsLogicType' +import type { TeamPublicType, TeamType } from '../../../types' const DEFAULT_INTERVAL = 'day' @@ -238,6 +251,105 @@ const convertDateFieldToDayJs = (date: string, timezone: string): Dayjs => { return dateStringToDayJs(date, timezone) ?? dayjs().tz(timezone) } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface appMetricsLogicValues { + currentTeam: TeamPublicType | TeamType | null // teamLogic + appMetricsTrends: AppMetricsTimeSeriesResponse | null + appMetricsTrendsLoading: boolean + appMetricsTrendsPreviousPeriod: AppMetricsTimeSeriesResponse | null + appMetricsTrendsPreviousPeriodLoading: boolean + availableIntervals: AppMetricsCommonParams['interval'][] + getDateRangeAbsolute: () => { + dateFrom: Dayjs + dateTo: Dayjs + diffMs: number + } + getSingleTrendSeries: (name: string, previousPeriod?: boolean) => AppMetricsTimeSeriesResponse | null + params: Partial +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface appMetricsLogicActions { + loadAppMetricsTrends: () => { + value: true + } + loadAppMetricsTrendsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadAppMetricsTrendsPreviousPeriod: () => { + value: true + } + loadAppMetricsTrendsPreviousPeriodFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadAppMetricsTrendsPreviousPeriodSuccess: ( + appMetricsTrendsPreviousPeriod: AppMetricsTimeSeriesResponse, + payload?: { + value: true + } + ) => { + appMetricsTrendsPreviousPeriod: AppMetricsTimeSeriesResponse + payload?: { + value: true + } + } + loadAppMetricsTrendsSuccess: ( + appMetricsTrends: AppMetricsTimeSeriesResponse, + payload?: { + value: true + } + ) => { + appMetricsTrends: AppMetricsTimeSeriesResponse + payload?: { + value: true + } + } + setParams: (params: Partial) => { + params: Partial + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface appMetricsLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + getSingleTrendSeries: ( + appMetricsTrends: AppMetricsTimeSeriesResponse | null, + appMetricsTrendsPreviousPeriod: AppMetricsTimeSeriesResponse | null + ) => (name: string, previousPeriod?: boolean) => AppMetricsTimeSeriesResponse | null + getDateRangeAbsolute: ( + params: Partial, + currentTeam: TeamPublicType | TeamType | null + ) => () => { + dateFrom: Dayjs + dateTo: Dayjs + diffMs: number + } + availableIntervals: ( + getDateRangeAbsolute: () => { + dateFrom: Dayjs + dateTo: Dayjs + diffMs: number + } + ) => AppMetricsCommonParams['interval'][] + } +} + +export type appMetricsLogicType = MakeLogicType< + appMetricsLogicValues, + appMetricsLogicActions, + AppMetricsLogicProps, + appMetricsLogicMeta +> + // IDEA - have a generic helper logic that can be used anywhere for rendering metrics export const appMetricsLogic = kea([ props({} as unknown as AppMetricsLogicProps), @@ -307,7 +419,10 @@ export const appMetricsLogic = kea([ selectors(() => ({ getSingleTrendSeries: [ (s) => [s.appMetricsTrends, s.appMetricsTrendsPreviousPeriod], - (appMetricsTrends, appMetricsTrendsPreviousPeriod) => + ( + appMetricsTrends: AppMetricsTimeSeriesResponse | null, + appMetricsTrendsPreviousPeriod: AppMetricsTimeSeriesResponse | null + ) => (name: string, previousPeriod: boolean = false): AppMetricsTimeSeriesResponse | null => { const targetTrend = previousPeriod ? appMetricsTrendsPreviousPeriod : appMetricsTrends if (!targetTrend) { @@ -327,23 +442,33 @@ export const appMetricsLogic = kea([ getDateRangeAbsolute: [ (s) => [s.params, s.currentTeam], - (params, currentTeam) => (): { dateFrom: Dayjs; dateTo: Dayjs; diffMs: number } => { - const dateFrom = convertDateFieldToDayJs(params.dateFrom ?? '-7d', currentTeam?.timezone ?? 'UTC') - const dateTo = params.dateTo - ? convertDateFieldToDayJs(params.dateTo, currentTeam?.timezone ?? 'UTC') - : dayjs() - .tz(currentTeam?.timezone ?? 'UTC') - .endOf(params.interval ?? DEFAULT_INTERVAL) - - const diffMs = dateTo.diff(dateFrom) - - return { dateFrom, dateTo, diffMs } - }, + ( + params: Partial, + currentTeam: null | import('../../../types').TeamPublicType | import('../../../types').TeamType + ) => + (): { dateFrom: Dayjs; dateTo: Dayjs; diffMs: number } => { + const dateFrom = convertDateFieldToDayJs(params.dateFrom ?? '-7d', currentTeam?.timezone ?? 'UTC') + const dateTo = params.dateTo + ? convertDateFieldToDayJs(params.dateTo, currentTeam?.timezone ?? 'UTC') + : dayjs() + .tz(currentTeam?.timezone ?? 'UTC') + .endOf(params.interval ?? DEFAULT_INTERVAL) + + const diffMs = dateTo.diff(dateFrom) + + return { dateFrom, dateTo, diffMs } + }, ], availableIntervals: [ (s) => [s.getDateRangeAbsolute], - (getDateRangeAbsolute): AppMetricsCommonParams['interval'][] => { + ( + getDateRangeAbsolute: () => { + dateFrom: Dayjs + dateTo: Dayjs + diffMs: number + } + ): AppMetricsCommonParams['interval'][] => { const diffMs = getDateRangeAbsolute().diffMs // If the diff is less than 2 days (ish), we can show the minute interval but not day diff --git a/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts b/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts index 72b25da4fd6f..d1e50338c1fb 100644 --- a/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts +++ b/frontend/src/lib/components/AuthorizedUrlList/authorizedUrlListLogic.ts @@ -1,4 +1,5 @@ import { + MakeLogicType, actions, afterMount, connect, @@ -11,7 +12,9 @@ import { selectors, sharedListeners, } from 'kea' +import type { BreakPointFunction } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { loaders } from 'kea-loaders' import { encodeParams, urlToAction } from 'kea-router' import { subscriptions } from 'kea-subscriptions' @@ -30,7 +33,7 @@ import { ProductIntentContext, ProductKey } from '~/queries/schema/schema-genera import { hogql } from '~/queries/utils' import { ExperimentIdType, ToolbarParams, ToolbarUserIntent } from '~/types' -import type { authorizedUrlListLogicType } from './authorizedUrlListLogicType' +import type { TeamPublicType, TeamType, UserType } from '../../../types' export interface ProposeNewUrlFormType { url: string @@ -305,6 +308,166 @@ export const defaultAuthorizedUrlProperties = { userIntent: undefined, } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface authorizedUrlListLogicValues { + currentTeam: TeamPublicType | TeamType | null // teamLogic + currentTeamId: number | null // teamLogic + user: UserType | null // userLogic + authorizedUrls: string[] + checkUrlIsAuthorized: (url: string) => boolean + checkUrlIsSafeToFrame: (url: string) => boolean + editUrlIndex: number | null + isAddUrlFormVisible: boolean + isProposedUrlSubmitting: boolean + isProposedUrlValid: boolean + launchUrl: (url: string) => string + onlyAllowDomains: boolean + proposedUrl: ProposeNewUrlFormType + proposedUrlAllErrors: Record + proposedUrlChanged: boolean + proposedUrlErrors: DeepPartialMap + proposedUrlHasErrors: boolean + proposedUrlManualErrors: Record + proposedUrlTouched: boolean + proposedUrlTouches: Record + proposedUrlValidationErrors: DeepPartialMap + showProposedURLForm: boolean + showProposedUrlErrors: boolean + suggestions: any[] + suggestionsLoading: boolean + urlToEdit: string + urlsKeyed: KeyedAppUrl[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface authorizedUrlListLogicActions { + updateCurrentTeam: (payload: Partial) => Partial // teamLogic + addUrl: ( + url: string, + launch?: boolean + ) => { + launch: boolean | undefined + url: string + } + cancelProposingUrl: () => { + value: true + } + copyLaunchCode: () => { + value: true + } + launchAtUrl: (url: string) => { + url: string + } + loadSuggestions: (_: void) => void + loadSuggestionsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadSuggestionsSuccess: ( + suggestions: SuggestedDomain[], + payload?: void + ) => { + suggestions: SuggestedDomain[] + payload?: void + } + newUrl: () => { + value: true + } + removeUrl: (index: number) => { + index: number + } + resetProposedUrl: (values?: ProposeNewUrlFormType) => { + values?: ProposeNewUrlFormType + } + setAuthorizedUrls: (authorizedUrls: string[]) => { + authorizedUrls: string[] + } + setEditUrlIndex: (originalIndex: number | null) => { + originalIndex: number | null + } + setProposedUrlManualErrors: (errors: Record) => { + errors: Record + } + setProposedUrlValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setProposedUrlValues: (values: DeepPartial) => { + values: DeepPartial + } + submitProposedUrl: () => { + value: boolean + } + submitProposedUrlFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitProposedUrlRequest: (proposedUrl: ProposeNewUrlFormType) => { + proposedUrl: ProposeNewUrlFormType + } + submitProposedUrlSuccess: (proposedUrl: ProposeNewUrlFormType) => { + proposedUrl: ProposeNewUrlFormType + } + touchProposedUrlField: (key: string) => { + key: string + } + updateUrl: ( + index: number, + url: string + ) => { + index: number + url: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface authorizedUrlListLogicMeta { + key: string + sharedListeners: { + saveUrls: ( + payload: any, + breakpoint: BreakPointFunction, + action: { + type: string + payload: any + }, + previousState: any + ) => void | Promise + } + __keaTypeGenInternalSelectorTypes: { + urlToEdit: (authorizedUrls: string[], editUrlIndex: number | null) => string + urlsKeyed: (authorizedUrls: string[], suggestions: any[]) => KeyedAppUrl[] + launchUrl: ( + currentTeam: TeamPublicType | TeamType | null, + user: UserType | null, + actionId: number | null, + experimentId: ExperimentIdType | null, + productTourId: string | null, + arg: ToolbarUserIntent | undefined + ) => (url: string) => string + isAddUrlFormVisible: (editUrlIndex: number | null) => boolean + onlyAllowDomains: (type: AuthorizedUrlListType) => boolean + checkUrlIsAuthorized: (authorizedUrls: string[]) => (url: string) => boolean + checkUrlIsSafeToFrame: (authorizedUrls: string[]) => (url: string) => boolean + } +} + +export type authorizedUrlListLogicType = MakeLogicType< + authorizedUrlListLogicValues, + authorizedUrlListLogicActions, + AuthorizedUrlListLogicProps, + authorizedUrlListLogicMeta +> + export const authorizedUrlListLogic = kea([ path((key) => ['lib', 'components', 'AuthorizedUrlList', 'authorizedUrlListLogic', key]), key((props) => `${props.type}-${props.experimentId}-${props.actionId}-${props.productTourId}`), // Some will be undefined but that's ok, this avoids experiment/action with same ID sharing same store @@ -509,7 +672,7 @@ export const authorizedUrlListLogic = kea([ selectors({ urlToEdit: [ (s) => [s.authorizedUrls, s.editUrlIndex], - (authorizedUrls, editUrlIndex) => { + (authorizedUrls: string[], editUrlIndex: number | null) => { if (editUrlIndex === null || editUrlIndex === -1) { return NEW_URL } @@ -518,7 +681,7 @@ export const authorizedUrlListLogic = kea([ ], urlsKeyed: [ (s) => [s.authorizedUrls, s.suggestions], - (authorizedUrls, suggestions): KeyedAppUrl[] => { + (authorizedUrls: string[], suggestions: any[]): KeyedAppUrl[] => { const keyedUrls = authorizedUrls .map((url, index) => ({ url, @@ -546,35 +709,46 @@ export const authorizedUrlListLogic = kea([ p.productTourId, p.userIntent ?? (() => undefined), ], - (currentTeam, user, actionId, experimentId, productTourId, userIntent) => (url: string) => { - const commonOptions = { - token: currentTeam?.api_token, - dataAttributes: currentTeam?.data_attributes, - userEmail: user?.email, - distinctId: user?.distinct_id, - } - if (experimentId) { - return directToolbarUrl(url, { ...commonOptions, experimentId }) - } - if (productTourId) { - return directToolbarUrl(url, { ...commonOptions, productTourId, userIntent }) - } - return directToolbarUrl(url, { ...commonOptions, actionId }) - }, + ( + currentTeam: null | import('~/types').TeamPublicType | import('~/types').TeamType, + user: null | import('~/types').UserType, + actionId: number | null, + experimentId: ExperimentIdType | null, + productTourId: string | null, + userIntent: ToolbarUserIntent | undefined + ) => + (url: string) => { + const commonOptions = { + token: currentTeam?.api_token, + dataAttributes: currentTeam?.data_attributes, + userEmail: user?.email, + distinctId: user?.distinct_id, + } + if (experimentId) { + return directToolbarUrl(url, { ...commonOptions, experimentId }) + } + if (productTourId) { + return directToolbarUrl(url, { ...commonOptions, productTourId, userIntent }) + } + return directToolbarUrl(url, { ...commonOptions, actionId }) + }, + ], + isAddUrlFormVisible: [(s) => [s.editUrlIndex], (editUrlIndex: number | null) => editUrlIndex === -1], + onlyAllowDomains: [ + (_, p) => [p.type], + (type: AuthorizedUrlListType) => type === AuthorizedUrlListType.RECORDING_DOMAINS, ], - isAddUrlFormVisible: [(s) => [s.editUrlIndex], (editUrlIndex) => editUrlIndex === -1], - onlyAllowDomains: [(_, p) => [p.type], (type) => type === AuthorizedUrlListType.RECORDING_DOMAINS], checkUrlIsAuthorized: [ (s) => [s.authorizedUrls], - (authorizedUrls) => (url: string) => { + (authorizedUrls: string[]) => (url: string) => { return checkUrlIsAuthorized(url, authorizedUrls) }, ], checkUrlIsSafeToFrame: [ (s) => [s.authorizedUrls], - (authorizedUrls) => (url: string) => { + (authorizedUrls: string[]) => (url: string) => { return checkUrlIsSafeToFrame(url, authorizedUrls) }, ], diff --git a/frontend/src/lib/components/Cards/ButtonTileCard/buttonTileCardModalLogic.ts b/frontend/src/lib/components/Cards/ButtonTileCard/buttonTileCardModalLogic.ts index 39bc5b916764..88cc58b33ce5 100644 --- a/frontend/src/lib/components/Cards/ButtonTileCard/buttonTileCardModalLogic.ts +++ b/frontend/src/lib/components/Cards/ButtonTileCard/buttonTileCardModalLogic.ts @@ -1,5 +1,6 @@ -import { connect, kea, key, listeners, path, props } from 'kea' +import { MakeLogicType, connect, kea, key, listeners, path, props } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import posthog from 'posthog-js' import { lemonToast } from '@posthog/lemon-ui' @@ -7,8 +8,6 @@ import { lemonToast } from '@posthog/lemon-ui' import { dashboardsModel } from '~/models/dashboardsModel' import { DashboardType, QueryBasedInsightModel } from '~/types' -import type { buttonTileCardModalLogicType } from './buttonTileCardModalLogicType' - export interface ButtonTileForm { url: string text: string @@ -55,6 +54,74 @@ const isValidPathname = (value: string): boolean => { return /^\/[a-zA-Z0-9._~:/?#[\]@!$&'()*+,;=%-]*$/.test(value) } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface buttonTileCardModalLogicValues { + buttonTile: ButtonTileForm + buttonTileAllErrors: Record + buttonTileChanged: boolean + buttonTileErrors: DeepPartialMap + buttonTileHasErrors: boolean + buttonTileManualErrors: Record + buttonTileTouched: boolean + buttonTileTouches: Record + buttonTileValidationErrors: DeepPartialMap + isButtonTileSubmitting: boolean + isButtonTileValid: boolean + showButtonTileErrors: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface buttonTileCardModalLogicActions { + updateDashboard: (args_0: any) => any // dashboardsModel + resetButtonTile: (values?: ButtonTileForm) => { + values?: ButtonTileForm + } + setButtonTileManualErrors: (errors: Record) => { + errors: Record + } + setButtonTileValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setButtonTileValues: (values: DeepPartial) => { + values: DeepPartial + } + submitButtonTile: () => { + value: boolean + } + submitButtonTileFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitButtonTileRequest: (buttonTile: ButtonTileForm) => { + buttonTile: ButtonTileForm + } + submitButtonTileSuccess: (buttonTile: ButtonTileForm) => { + buttonTile: ButtonTileForm + } + touchButtonTileField: (key: string) => { + key: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface buttonTileCardModalLogicMeta { + key: string +} + +export type buttonTileCardModalLogicType = MakeLogicType< + buttonTileCardModalLogicValues, + buttonTileCardModalLogicActions, + ButtonTileCardModalProps, + buttonTileCardModalLogicMeta +> + export const buttonTileCardModalLogic = kea([ path(['scenes', 'dashboard', 'buttonTileCardModal', 'logic']), props({} as ButtonTileCardModalProps), diff --git a/frontend/src/lib/components/Cards/InsightCard/dashboardWidgetMenusLogic.ts b/frontend/src/lib/components/Cards/InsightCard/dashboardWidgetMenusLogic.ts index 4c2c28825cc2..8443d0cba807 100644 --- a/frontend/src/lib/components/Cards/InsightCard/dashboardWidgetMenusLogic.ts +++ b/frontend/src/lib/components/Cards/InsightCard/dashboardWidgetMenusLogic.ts @@ -1,11 +1,12 @@ -import { connect, kea, key, path, props, selectors } from 'kea' +import { MakeLogicType, connect, kea, key, path, props, selectors } from 'kea' import { accessLevelSatisfied } from 'lib/utils/accessControlUtils' import { dashboardsModel } from '~/models/dashboardsModel' import { AccessControlLevel, AccessControlResourceType, DashboardBasicType, DashboardTileBasicType } from '~/types' -import type { dashboardWidgetMenusLogicType } from './dashboardWidgetMenusLogicType' +import type { Node } from '../../../../queries/schema/schema-general' +import type { DashboardType, QueryBasedInsightModel } from '../../../../types' import type { DashboardWidgetPlacementDestination } from './DashboardWidgetPlacementMenu' /** Stable key for kea; e.g. insight short_id, `text-${id}`, `button-${id}`, or `text-tile-${tileId}`. */ @@ -22,6 +23,40 @@ function canEditDestinationDashboard(d: DashboardBasicType): boolean { : true } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dashboardWidgetMenusLogicValues { + nameSortedDashboards: (DashboardBasicType | DashboardType>>>)[] // dashboardsModel + copyToDestinations: DashboardWidgetPlacementDestination[] + dashboardIdsWithThisWidget: Set +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dashboardWidgetMenusLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + dashboardIdsWithThisWidget: ( + dashboards: number[] | null | undefined, + dashboard_tiles: DashboardTileBasicType[] | null | undefined, + dashboardId: number | null | undefined + ) => Set + copyToDestinations: ( + nameSortedDashboards: ( + | DashboardBasicType + | DashboardType>>> + )[], + dashboardIdsWithThisWidget: Set, + dashboardId: number | null | undefined + ) => DashboardWidgetPlacementDestination[] + } +} + +export type dashboardWidgetMenusLogicType = MakeLogicType< + dashboardWidgetMenusLogicValues, + {}, + DashboardWidgetMenusLogicProps, + dashboardWidgetMenusLogicMeta +> + /** Copy / Move dashboard submenus for insight, text, and button widgets (placement + ACL). */ export const dashboardWidgetMenusLogic = kea([ path(['lib', 'components', 'Cards', 'InsightCard', 'dashboardWidgetMenusLogic']), @@ -59,7 +94,18 @@ export const dashboardWidgetMenusLogic = kea([ /** Destinations for Copy to and Move to submenus (disabled rows explain why a target is unavailable). */ copyToDestinations: [ (s, p) => [s.nameSortedDashboards, s.dashboardIdsWithThisWidget, p.dashboardId], - (nameSortedDashboards, dashboardIdsWithThisWidget, dashboardId): DashboardWidgetPlacementDestination[] => { + ( + nameSortedDashboards: ( + | DashboardBasicType + | import('~/types').DashboardType< + import('~/types').QueryBasedInsightModel< + import('../../../../queries/schema').Node> + > + > + )[], + dashboardIdsWithThisWidget: Set, + dashboardId: number | null | undefined + ): DashboardWidgetPlacementDestination[] => { return nameSortedDashboards .filter((d) => (dashboardId == null || d.id !== dashboardId) && canEditDestinationDashboard(d)) .map((d) => ({ diff --git a/frontend/src/lib/components/Cards/TextCard/textCardModalLogic.ts b/frontend/src/lib/components/Cards/TextCard/textCardModalLogic.ts index 6d5dc5dd754d..113472db2918 100644 --- a/frontend/src/lib/components/Cards/TextCard/textCardModalLogic.ts +++ b/frontend/src/lib/components/Cards/TextCard/textCardModalLogic.ts @@ -1,5 +1,6 @@ -import { connect, kea, key, listeners, path, props } from 'kea' +import { MakeLogicType, connect, kea, key, listeners, path, props } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import posthog from 'posthog-js' import { lemonToast } from '@posthog/lemon-ui' @@ -7,8 +8,6 @@ import { lemonToast } from '@posthog/lemon-ui' import { dashboardsModel } from '~/models/dashboardsModel' import { DashboardTile, DashboardType, QueryBasedInsightModel } from '~/types' -import type { textCardModalLogicType } from './textCardModalLogicType' - export interface TextTileForm { body: string transparent_background: boolean @@ -30,6 +29,74 @@ const getExistingTextTile = (dashboard: DashboardType, t } } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface textCardModalLogicValues { + isTextTileSubmitting: boolean + isTextTileValid: boolean + showTextTileErrors: boolean + textTile: TextTileForm + textTileAllErrors: Record + textTileChanged: boolean + textTileErrors: DeepPartialMap + textTileHasErrors: boolean + textTileManualErrors: Record + textTileTouched: boolean + textTileTouches: Record + textTileValidationErrors: DeepPartialMap +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface textCardModalLogicActions { + updateDashboard: (args_0: any) => any // dashboardsModel + resetTextTile: (values?: TextTileForm) => { + values?: TextTileForm + } + setTextTileManualErrors: (errors: Record) => { + errors: Record + } + setTextTileValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setTextTileValues: (values: DeepPartial) => { + values: DeepPartial + } + submitTextTile: () => { + value: boolean + } + submitTextTileFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitTextTileRequest: (textTile: TextTileForm) => { + textTile: TextTileForm + } + submitTextTileSuccess: (textTile: TextTileForm) => { + textTile: TextTileForm + } + touchTextTileField: (key: string) => { + key: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface textCardModalLogicMeta { + key: string +} + +export type textCardModalLogicType = MakeLogicType< + textCardModalLogicValues, + textCardModalLogicActions, + TextCardModalProps, + textCardModalLogicMeta +> + export const textCardModalLogic = kea([ path(['scenes', 'dashboard', 'dashboardTextTileModal', 'logic']), props({} as TextCardModalProps), diff --git a/frontend/src/lib/components/Command/commandLogic.tsx b/frontend/src/lib/components/Command/commandLogic.tsx index 090c6ca1c417..aac5fbddf83b 100644 --- a/frontend/src/lib/components/Command/commandLogic.tsx +++ b/frontend/src/lib/components/Command/commandLogic.tsx @@ -1,6 +1,24 @@ -import { actions, kea, path, reducers } from 'kea' +import { MakeLogicType, actions, kea, path, reducers } from 'kea' -import type { commandLogicType } from './commandLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface commandLogicValues { + isCommandOpen: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface commandLogicActions { + closeCommand: () => { + value: true + } + openCommand: () => { + value: true + } + toggleCommand: () => { + value: true + } +} + +export type commandLogicType = MakeLogicType export const commandLogic = kea([ path(['lib', 'components', 'Command', 'commandLogic']), diff --git a/frontend/src/lib/components/CyclotronJob/cyclotronJobInputLogic.ts b/frontend/src/lib/components/CyclotronJob/cyclotronJobInputLogic.ts index 3f9c03716ad9..6bd1fa23173b 100644 --- a/frontend/src/lib/components/CyclotronJob/cyclotronJobInputLogic.ts +++ b/frontend/src/lib/components/CyclotronJob/cyclotronJobInputLogic.ts @@ -1,6 +1,4 @@ -import { kea } from 'kea' - -import type { cyclotronJobInputLogicType } from './cyclotronJobInputLogicType' +import { MakeLogicType, kea } from 'kea' export interface CyclotronJobInputLogicProps { fieldKey: string @@ -19,6 +17,41 @@ export function formatJsonValue(value: any): string { return typeof value !== 'string' ? JSON.stringify(value, null, 2) : value } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface cyclotronJobInputLogicValues { + error: string | null + hasError: boolean + jsonValue: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface cyclotronJobInputLogicActions { + setError: (error: string | null) => { + error: string | null + } + setJsonValue: (value: string) => { + value: string + } + validateJson: (value: string) => { + value: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface cyclotronJobInputLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + hasError: (error: any) => boolean + } +} + +export type cyclotronJobInputLogicType = MakeLogicType< + cyclotronJobInputLogicValues, + cyclotronJobInputLogicActions, + CyclotronJobInputLogicProps, + cyclotronJobInputLogicMeta +> + export const cyclotronJobInputLogic = kea({ path: ['lib', 'components', 'CyclotronJob', 'cyclotronJobInputLogic'], props: {} as CyclotronJobInputLogicProps, diff --git a/frontend/src/lib/components/CyclotronJob/cyclotronJobTemplateSuggestionsLogic.tsx b/frontend/src/lib/components/CyclotronJob/cyclotronJobTemplateSuggestionsLogic.tsx index c8f4c338669b..98ff8d382f33 100644 --- a/frontend/src/lib/components/CyclotronJob/cyclotronJobTemplateSuggestionsLogic.tsx +++ b/frontend/src/lib/components/CyclotronJob/cyclotronJobTemplateSuggestionsLogic.tsx @@ -1,12 +1,10 @@ import FuseClass from 'fuse.js' -import { actions, kea, key, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, kea, key, path, props, reducers, selectors } from 'kea' import { STL as HOG_STL } from '@posthog/hogvm' import { createFuse } from 'lib/utils/fuseSearch' -import type { cyclotronJobTemplateSuggestionsLogicType } from './cyclotronJobTemplateSuggestionsLogicType' - export type CyclotronJobTemplateOption = { key: string description: string @@ -77,6 +75,42 @@ const LIQUID_USAGE_EXAMPLES: CyclotronJobTemplateOption[] = [ }, ] +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface cyclotronJobTemplateSuggestionsLogicValues { + allOptions: CyclotronJobTemplateOption[] + optionsFiltered: CyclotronJobTemplateOption[] + optionsFuse: Fuse + search: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface cyclotronJobTemplateSuggestionsLogicActions { + setSearch: (search: string) => { + search: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface cyclotronJobTemplateSuggestionsLogicMeta { + key: 'hog' | 'liquid' + __keaTypeGenInternalSelectorTypes: { + allOptions: (templating: 'hog' | 'liquid') => CyclotronJobTemplateOption[] + optionsFuse: (allOptions: CyclotronJobTemplateOption[]) => Fuse + optionsFiltered: ( + allOptions: CyclotronJobTemplateOption[], + optionsFuse: Fuse, + search: string + ) => CyclotronJobTemplateOption[] + } +} + +export type cyclotronJobTemplateSuggestionsLogicType = MakeLogicType< + cyclotronJobTemplateSuggestionsLogicValues, + cyclotronJobTemplateSuggestionsLogicActions, + CyclotronJobTemplateSuggestionsLogicProps, + cyclotronJobTemplateSuggestionsLogicMeta +> + export const cyclotronJobTemplateSuggestionsLogic = kea([ props({} as CyclotronJobTemplateSuggestionsLogicProps), key(({ templating }: CyclotronJobTemplateSuggestionsLogicProps) => templating), @@ -92,14 +126,14 @@ export const cyclotronJobTemplateSuggestionsLogic = kea [p.templating], - (templating): CyclotronJobTemplateOption[] => { + (templating: 'hog' | 'liquid'): CyclotronJobTemplateOption[] => { return templating === 'hog' ? [...HOG_USAGE_EXAMPLES, ...HOG_STL_EXAMPLES] : LIQUID_USAGE_EXAMPLES }, ], optionsFuse: [ (s) => [s.allOptions], - (allOptions): Fuse => { + (allOptions: CyclotronJobTemplateOption[]): Fuse => { return createFuse(allOptions, { keys: ['description', 'example'], }) @@ -108,7 +142,11 @@ export const cyclotronJobTemplateSuggestionsLogic = kea [s.allOptions, s.optionsFuse, s.search], - (allOptions, optionsFuse, search): CyclotronJobTemplateOption[] => { + ( + allOptions: CyclotronJobTemplateOption[], + optionsFuse: Fuse, + search: string + ): CyclotronJobTemplateOption[] => { if (!search) { return allOptions } diff --git a/frontend/src/lib/components/DateFilter/DateRangePicker/dateRangePickerLogic.ts b/frontend/src/lib/components/DateFilter/DateRangePicker/dateRangePickerLogic.ts index 96088a81147d..6254d4347131 100644 --- a/frontend/src/lib/components/DateFilter/DateRangePicker/dateRangePickerLogic.ts +++ b/frontend/src/lib/components/DateFilter/DateRangePicker/dateRangePickerLogic.ts @@ -1,9 +1,7 @@ -import { actions, kea, key, path, props, reducers } from 'kea' +import { MakeLogicType, actions, kea, key, path, props, reducers } from 'kea' import { DateRange } from '~/queries/schema/schema-general' -import type { dateRangePickerLogicType } from './dateRangePickerLogicType' - const MAX_HISTORY_ITEMS = 5 const dateRangesEqual = (a: DateRange, b: DateRange): boolean => a.date_from === b.date_from && a.date_to === b.date_to @@ -13,6 +11,42 @@ export interface DateRangePickerLogicProps { key: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dateRangePickerLogicValues { + customFrom: string + customTo: string + history: DateRange[] + popoverOpen: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dateRangePickerLogicActions { + addToHistory: (dateRange: DateRange) => { + dateRange: DateRange + } + setCustomFrom: (value: string) => { + value: string + } + setCustomTo: (value: string) => { + value: string + } + setPopoverOpen: (open: boolean) => { + open: boolean + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dateRangePickerLogicMeta { + key: string +} + +export type dateRangePickerLogicType = MakeLogicType< + dateRangePickerLogicValues, + dateRangePickerLogicActions, + DateRangePickerLogicProps, + dateRangePickerLogicMeta +> + export const dateRangePickerLogic = kea([ props({} as DateRangePickerLogicProps), key((props) => props.key), diff --git a/frontend/src/lib/components/DateFilter/dateFilterLogic.ts b/frontend/src/lib/components/DateFilter/dateFilterLogic.ts index 8efd658fcabc..9eea9d95b76a 100644 --- a/frontend/src/lib/components/DateFilter/dateFilterLogic.ts +++ b/frontend/src/lib/components/DateFilter/dateFilterLogic.ts @@ -1,4 +1,4 @@ -import { actions, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { DateFilterLogicProps, @@ -12,8 +12,6 @@ import { formatDate, formatDateRange, formatDateTime, formatDateTimeRange, isDat import { DateMappingOption } from '~/types' -import type { dateFilterLogicType } from './dateFilterLogicType' - const RELATIVE_UNIT_LABEL: Record = { h: 'hour', d: 'day', @@ -47,6 +45,136 @@ function hasTimePrecision(dateValue: string | Dayjs | null | undefined): boolean return false } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dateFilterLogicValues { + dateFrom: any + dateFromHasTimePrecision: boolean + dateOptions: DateMappingOption[] | undefined + dateTo: any + dateToHasTimePrecision: boolean + explicitDate: boolean + fixedRangeGranularity: 'day' | 'minute' + isCustomRelativeRange: boolean + isCustomRelativeRangeView: boolean + isDateToNow: boolean + isFixedDate: any + isFixedRange: boolean + isFixedRangeWithTime: boolean + isRollingDateRange: boolean + isVisible: boolean + label: string | null + rangeDateFrom: Dayjs | null + rangeDateTo: Dayjs | null + view: DateFilterView +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dateFilterLogicActions { + applyRange: () => { + value: true + } + close: () => { + value: true + } + open: () => { + value: true + } + openCustomRelativeRange: () => { + value: true + } + openDateToNow: () => { + value: true + } + openFixedDate: () => { + value: true + } + openFixedRange: () => { + value: true + } + openFixedRangeWithTime: () => { + value: true + } + openJumpToTimestamp: () => { + value: true + } + setDate: ( + dateFrom: string | null, + dateTo: string | null, + keepPopoverOpen?: any, + explicitDate?: boolean + ) => { + dateFrom: string | null + dateTo: string | null + explicitDate: boolean + keepPopoverOpen: any + } + setExplicitDate: (explicitDate: boolean) => { + explicitDate: boolean + } + setFixedRangeGranularity: (granularity: 'day' | 'minute') => { + granularity: 'day' | 'minute' + } + setRangeDateFrom: (range: Dayjs | null) => { + range: Dayjs | null + } + setRangeDateTo: (range: Dayjs | null) => { + range: Dayjs | null + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface dateFilterLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + dateFrom: (arg: any) => any + dateTo: (arg: any) => any + dateOptions: (arg: any) => DateMappingOption[] | undefined + isFixedRange: (dateFrom: any, dateTo: any) => boolean + isFixedRangeWithTime: ( + isFixedRange: boolean, + dateFromHasTimePrecision: boolean, + dateToHasTimePrecision: boolean + ) => boolean + isDateToNow: (dateFrom: any, dateTo: any, arg: any) => boolean + isFixedDate: (dateFrom: any, dateTo: any, arg: any) => any + isRollingDateRange: ( + isFixedRange: boolean, + isDateToNow: boolean, + isFixedDate: any, + dateOptions: DateMappingOption[] | undefined, + dateFrom: any, + dateTo: any + ) => boolean + isCustomRelativeRange: (dateFrom: any, dateTo: any) => boolean + isCustomRelativeRangeView: (view: DateFilterView) => boolean + dateFromHasTimePrecision: (dateFrom: any) => boolean + dateToHasTimePrecision: (dateTo: any) => boolean + label: ( + dateFrom: any, + dateTo: any, + isFixedRange: boolean, + isDateToNow: boolean, + isFixedDate: any, + isCustomRelativeRange: boolean, + dateOptions: DateMappingOption[] | undefined, + arg: any, + arg2: any, + arg3: any, + arg4: any, + arg5: any, + dateFromHasTimePrecision: boolean, + dateToHasTimePrecision: boolean + ) => string | null + } +} + +export type dateFilterLogicType = MakeLogicType< + dateFilterLogicValues, + dateFilterLogicActions, + DateFilterLogicProps, + dateFilterLogicMeta +> + export const dateFilterLogic = kea([ path(['lib', 'components', 'DateFilter', 'DateFilterLogic']), props({} as DateFilterLogicProps), @@ -150,7 +278,7 @@ export const dateFilterLogic = kea([ ], isFixedRangeWithTime: [ (s) => [s.isFixedRange, s.dateFromHasTimePrecision, s.dateToHasTimePrecision], - (isFixedRange, dateFromHasTimePrecision, dateToHasTimePrecision) => + (isFixedRange: boolean, dateFromHasTimePrecision: boolean, dateToHasTimePrecision: boolean) => isFixedRange && (dateFromHasTimePrecision || dateToHasTimePrecision), ], isDateToNow: [ @@ -164,7 +292,14 @@ export const dateFilterLogic = kea([ ], isRollingDateRange: [ (s) => [s.isFixedRange, s.isDateToNow, s.isFixedDate, s.dateOptions, s.dateFrom, s.dateTo], - (isFixedRange, isDateToNow, isFixedDate, dateOptions, dateFrom, dateTo): boolean => + ( + isFixedRange: boolean, + isDateToNow: boolean, + isFixedDate, + dateOptions: DateMappingOption[] | undefined, + dateFrom, + dateTo + ): boolean => !isFixedRange && !isDateToNow && !isFixedDate && @@ -183,7 +318,10 @@ export const dateFilterLogic = kea([ return isRelativeFromDate && isRelativeToDate && !!dateFrom && !!dateTo }, ], - isCustomRelativeRangeView: [(s) => [s.view], (view): boolean => view === DateFilterView.CustomRelativeRange], + isCustomRelativeRangeView: [ + (s) => [s.view], + (view: DateFilterView): boolean => view === DateFilterView.CustomRelativeRange, + ], dateFromHasTimePrecision: [(s) => [s.dateFrom], (dateFrom) => hasTimePrecision(dateFrom)], dateToHasTimePrecision: [(s) => [s.dateTo], (dateTo) => hasTimePrecision(dateTo)], label: [ @@ -206,18 +344,18 @@ export const dateFilterLogic = kea([ ( dateFrom, dateTo, - isFixedRange, - isDateToNow, + isFixedRange: boolean, + isDateToNow: boolean, isFixedDate, - isCustomRelativeRange, - dateOptions, + isCustomRelativeRange: boolean, + dateOptions: DateMappingOption[] | undefined, isFixedDateMode, placeholder, allowTimePrecision, showCustomRelativeRange, allowSingleAndRange, - dateFromHasTimePrecision, - dateToHasTimePrecision + dateFromHasTimePrecision: boolean, + dateToHasTimePrecision: boolean ) => { // Only render the "N days ago to M days ago" label when the consumer has opted into // the custom-relative-range picker — other call sites (e.g. trends) may legitimately diff --git a/frontend/src/lib/components/DateFilter/rollingDateRangeFilterLogic.ts b/frontend/src/lib/components/DateFilter/rollingDateRangeFilterLogic.ts index d162b77c7b72..9d7d07872217 100644 --- a/frontend/src/lib/components/DateFilter/rollingDateRangeFilterLogic.ts +++ b/frontend/src/lib/components/DateFilter/rollingDateRangeFilterLogic.ts @@ -1,12 +1,10 @@ import './RollingDateRangeFilter.scss' -import { actions, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { Dayjs } from 'lib/dayjs' import { dateFilterToText } from 'lib/utils/dateFilters' -import type { rollingDateRangeFilterLogicType } from './rollingDateRangeFilterLogicType' - const dateOptionsMap = { y: 'years', q: 'quarters', @@ -48,6 +46,55 @@ const dateOptionDefault = (dateFrom: Dayjs | string | null | undefined): DateOpt return 'days' } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface rollingDateRangeFilterLogicValues { + counter: number | null + dateOption: DateOption + formattedDate: string | null + isDateOptionsSelectorOpen: boolean + startOfDateRange: string | null + value: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface rollingDateRangeFilterLogicActions { + decreaseCounter: () => { + value: true + } + increaseCounter: () => { + value: true + } + select: () => { + value: true + } + setCounter: (counter: number | null | undefined) => { + counter: number | null | undefined + } + setDateOption: (option: DateOption) => { + option: DateOption + } + toggleDateOptionsSelector: () => { + value: true + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface rollingDateRangeFilterLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + value: (counter: number | null, dateOption: DateOption) => string + formattedDate: (value: string) => string | null + startOfDateRange: (value: string) => string | null + } +} + +export type rollingDateRangeFilterLogicType = MakeLogicType< + rollingDateRangeFilterLogicValues, + rollingDateRangeFilterLogicActions, + RollingDateFilterLogicPropsType, + rollingDateRangeFilterLogicMeta +> + export const rollingDateRangeFilterLogic = kea([ path(['lib', 'components', 'DateFilter', 'RollingDateRangeFilterLogic']), props({} as RollingDateFilterLogicPropsType), @@ -97,7 +144,7 @@ export const rollingDateRangeFilterLogic = kea( selectors(() => ({ value: [ (s) => [s.counter, s.dateOption], - (counter, dateOption) => { + (counter: number | null, dateOption: DateOption) => { if (!counter) { return '' } diff --git a/frontend/src/lib/components/DefinitionPopover/definitionPopoverLogic.ts b/frontend/src/lib/components/DefinitionPopover/definitionPopoverLogic.ts index dea1422a02ee..a992ab167a09 100644 --- a/frontend/src/lib/components/DefinitionPopover/definitionPopoverLogic.ts +++ b/frontend/src/lib/components/DefinitionPopover/definitionPopoverLogic.ts @@ -1,5 +1,5 @@ import { deepEqual as equal } from 'fast-equals' -import { actions, connect, events, kea, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, events, kea, listeners, path, props, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' @@ -20,7 +20,8 @@ import { ActionType, CohortType, EventDefinition, PropertyDefinition } from '~/t import { DataWarehouseTableForInsight } from 'products/data_warehouse/frontend/types' -import type { definitionPopoverLogicType } from './definitionPopoverLogicType' +import type { TaxonomicFilterValue } from '../TaxonomicFilter/types' +import type { PropertyDefinitionType } from '../../../types' const IS_TEST_MODE = process.env.NODE_ENV === 'test' @@ -42,6 +43,106 @@ export interface DefinitionPopoverLogicProps { openDetailInNewTab?: boolean } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface definitionPopoverLogicValues { + getPropertyDefinition: (s: TaxonomicFilterValue, type: PropertyDefinitionType, groupTypeIndex?: number) => PropertyDefinition | null; // propertyDefinitionsModel + currentProjectId: number | string; // teamLogic + definition: Partial; + definitionLoading: boolean; + dirty: boolean; + hasSentAs: any; + hideEdit: any; + hideView: any; + isAction: boolean; + isCohort: boolean; + isDataWarehouse: boolean; + isDataWarehousePersonProperty: boolean; + isEvent: boolean; + isProperty: any; + isViewable: boolean; + isVirtual: boolean | undefined; + localDefinition: Partial; + mediaPreviews: string[]; + openDetailInNewTab: any; + resolvedDefinition: Partial; + singularType: string; + state: DefinitionPopoverState; + type: any; + viewFullDetailUrl: string | undefined; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface definitionPopoverLogicActions { + handleCancel: () => { + value: true; + }; + handleSave: (_: any) => any; + handleSaveFailure: (error: string, errorObject?: any) => { + error: string; + errorObject?: any; + }; + handleSaveSuccess: (definition: Partial, payload?: any) => { + definition: Partial; + payload?: any; + }; + recordHoverActivity: () => { + value: true; + }; + setDefinition: (item: Partial) => { + isDataWarehouse: boolean; + item: Partial; + selectedItemMeta: Record | null | undefined; + }; + setDefinitionFailure: (error: string, errorObject?: any) => { + error: string; + errorObject?: any; + }; + setDefinitionSuccess: (definition: TaxonomicDefinitionTypes, payload?: { + isDataWarehouse: boolean; + item: Partial; + selectedItemMeta: Record | null | undefined; + }) => { + definition: TaxonomicDefinitionTypes; + payload?: { + isDataWarehouse: boolean; + item: Partial; + selectedItemMeta: Record | null | undefined; + }; + }; + setLocalDefinition: (item: Partial) => { + item: Partial; + }; + setPopoverState: (state: DefinitionPopoverState) => { + state: DefinitionPopoverState; + }; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface definitionPopoverLogicMeta { + __keaTypeGenInternalSelectorTypes: { + type: (arg: any) => any; + hideView: (arg: any) => any; + hideEdit: (arg: any) => any; + openDetailInNewTab: (arg: any) => any; + singularType: (type: any) => string; + mediaPreviews: (definition: Partial) => string[]; + dirty: (state: DefinitionPopoverState, definition: Partial, localDefinition: Partial) => boolean; + isViewable: (type: any) => boolean; + isAction: (type: any) => boolean; + isEvent: (type: any) => boolean; + isProperty: (type: any) => any; + isVirtual: (definition: Partial) => boolean | undefined; + hasSentAs: (type: any, isProperty: any, isEvent: boolean, isVirtual: boolean | undefined) => any; + isCohort: (type: any) => boolean; + isDataWarehouse: (type: any) => boolean; + isDataWarehousePersonProperty: (type: any) => boolean; + resolvedDefinition: (definition: Partial, isProperty: any, type: any, getPropertyDefinition: (s: TaxonomicFilterValue, type: PropertyDefinitionType, groupTypeIndex?: number) => PropertyDefinition | null) => Partial; + viewFullDetailUrl: (resolvedDefinition: Partial, isAction: boolean, isEvent: boolean, isProperty: any, isCohort: boolean) => string | undefined; + }; +} + +export type definitionPopoverLogicType = MakeLogicType; + export const definitionPopoverLogic = kea([ props({} as DefinitionPopoverLogicProps), path(['lib', 'components', 'DefinitionPanel', 'definitionPopoverLogic']), @@ -170,11 +271,11 @@ export const definitionPopoverLogic = kea([ singularType: [(s) => [s.type], (type) => getSingularType(type)], mediaPreviews: [ (s) => [s.definition], - (definition): string[] => (definition as EventDefinition)?.media_preview_urls ?? [], + (definition: Partial): string[] => (definition as EventDefinition)?.media_preview_urls ?? [], ], dirty: [ (s) => [s.state, s.definition, s.localDefinition], - (state, definition, localDefinition) => + (state: DefinitionPopoverState, definition: Partial, localDefinition: Partial) => state === DefinitionPopoverState.Edit && !equal(definition, localDefinition), ], isViewable: [ @@ -219,13 +320,13 @@ export const definitionPopoverLogic = kea([ ], isVirtual: [ (s) => [s.definition], - (definition) => { + (definition: Partial) => { return 'virtual' in definition && definition.virtual }, ], hasSentAs: [ (s) => [s.type, s.isProperty, s.isEvent, s.isVirtual], - (type, isProperty, isEvent, isVirtual) => + (type, isProperty, isEvent: boolean, isVirtual: boolean | undefined) => isEvent || (isProperty && !isVirtual && type !== TaxonomicFilterGroupType.SessionProperties), ], isCohort: [(s) => [s.type], (type) => type === TaxonomicFilterGroupType.Cohorts], @@ -236,7 +337,7 @@ export const definitionPopoverLogic = kea([ ], resolvedDefinition: [ (s) => [s.definition, s.isProperty, s.type, s.getPropertyDefinition], - (definition, isProperty, type, getPropertyDefinition): Partial => { + (definition: Partial, isProperty, type, getPropertyDefinition: (s: TaxonomicFilterValue, type: PropertyDefinitionType, groupTypeIndex?: number) => PropertyDefinition | null): Partial => { // Pinned/default property items are stored as { name } only. Hydrate them with the // saved definition id recovered from propertyDefinitionsModel so View, Edit and Save // all operate on a complete definition (and self-heal as the model loads) rather @@ -258,7 +359,7 @@ export const definitionPopoverLogic = kea([ ], viewFullDetailUrl: [ (s) => [s.resolvedDefinition, s.isAction, s.isEvent, s.isProperty, s.isCohort], - (resolvedDefinition, isAction, isEvent, isProperty, isCohort) => { + (resolvedDefinition: Partial, isAction: boolean, isEvent: boolean, isProperty, isCohort: boolean) => { if (isAction) { const id = (resolvedDefinition as ActionType).id return id != null ? urls.action(id) : undefined diff --git a/frontend/src/lib/components/DomainConnect/domainConnectLogic.ts b/frontend/src/lib/components/DomainConnect/domainConnectLogic.ts index 3e3297ca7f98..a2a9f2caa801 100644 --- a/frontend/src/lib/components/DomainConnect/domainConnectLogic.ts +++ b/frontend/src/lib/components/DomainConnect/domainConnectLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, kea, key, listeners, path, props, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, kea, key, listeners, path, props, selectors } from 'kea' import { loaders } from 'kea-loaders' import { router } from 'kea-router' @@ -7,8 +7,6 @@ import { lemonToast } from 'lib/lemon-ui/LemonToast' import { DomainConnectProviderName } from '~/queries/schema/schema-general' -import type { domainConnectLogicType } from './domainConnectLogicType' - export interface DomainConnectProvider { endpoint: string name: DomainConnectProviderName @@ -33,6 +31,62 @@ export interface DomainConnectLogicProps { proxyRecordId?: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface domainConnectLogicValues { + autoDetected: boolean + availableProviders: DomainConnectProvider[] + domainConnectInfo: any + domainConnectInfoLoading: boolean + hasAnyOption: boolean + providerName: DomainConnectProviderName | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface domainConnectLogicActions { + checkDomain: () => { + value: true + } + checkDomainFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + checkDomainSuccess: ( + domainConnectInfo: DomainConnectInfo | null, + payload?: { + value: true + } + ) => { + domainConnectInfo: DomainConnectInfo | null + payload?: { + value: true + } + } + openDomainConnect: (providerEndpoint?: string) => { + providerEndpoint: string | undefined + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface domainConnectLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + autoDetected: (domainConnectInfo: any) => boolean + providerName: (domainConnectInfo: any) => DomainConnectProviderName | null + availableProviders: (domainConnectInfo: any) => DomainConnectProvider[] + hasAnyOption: (autoDetected: boolean, availableProviders: DomainConnectProvider[]) => boolean + } +} + +export type domainConnectLogicType = MakeLogicType< + domainConnectLogicValues, + domainConnectLogicActions, + DomainConnectLogicProps, + domainConnectLogicMeta +> + export const domainConnectLogic = kea([ path((key) => ['lib', 'components', 'DomainConnect', 'domainConnectLogic', key]), props({} as DomainConnectLogicProps), diff --git a/frontend/src/lib/components/Errors/Frame/framesCodeSourceLogic.ts b/frontend/src/lib/components/Errors/Frame/framesCodeSourceLogic.ts index 2df9c5a90419..af9aefe4ce4f 100644 --- a/frontend/src/lib/components/Errors/Frame/framesCodeSourceLogic.ts +++ b/frontend/src/lib/components/Errors/Frame/framesCodeSourceLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers, selectors } from 'kea' import { subscriptions } from 'kea-subscriptions' import { match } from 'ts-pattern' @@ -9,14 +9,47 @@ import { import api from 'lib/api' -import type { framesCodeSourceLogicType } from './framesCodeSourceLogicType' import { stackFrameLogic } from './stackFrameLogic' +import type { KeyedStackFrameRecords } from './stackFrameLogic' export interface SourceData { url: string provider: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface framesCodeSourceLogicValues { + stackFrameRecords: KeyedStackFrameRecords // stackFrameLogic + frameSourceUrls: Record + getSourceDataForFrame: (rawId: string) => SourceData | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface framesCodeSourceLogicActions { + computeSourceUrls: () => { + value: true + } + setSourceData: (data: Record) => { + data: Record + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface framesCodeSourceLogicMeta { + __keaTypeGenInternalSelectorTypes: { + getSourceDataForFrame: ( + frameSourceUrls: Record + ) => (rawId: string) => SourceData | null + } +} + +export type framesCodeSourceLogicType = MakeLogicType< + framesCodeSourceLogicValues, + framesCodeSourceLogicActions, + Record, + framesCodeSourceLogicMeta +> + export const framesCodeSourceLogic = kea([ path(['components', 'Errors', 'framesCodeSourceLogic']), diff --git a/frontend/src/lib/components/Errors/Frame/stackFrameLogic.ts b/frontend/src/lib/components/Errors/Frame/stackFrameLogic.ts index 4f52e4ef6a46..a1272d49eca6 100644 --- a/frontend/src/lib/components/Errors/Frame/stackFrameLogic.ts +++ b/frontend/src/lib/components/Errors/Frame/stackFrameLogic.ts @@ -1,11 +1,10 @@ -import { actions, afterMount, kea, listeners, path } from 'kea' +import { MakeLogicType, actions, afterMount, kea, listeners, path } from 'kea' import { loaders } from 'kea-loaders' import posthog from 'posthog-js' import api from 'lib/api' import { ErrorTrackingStackFrame, ErrorTrackingStackFrameRecord, ErrorTrackingSymbolSet } from '../types' -import type { stackFrameLogicType } from './stackFrameLogicType' export type KeyedStackFrameRecords = Record @@ -22,6 +21,60 @@ function mapStackFrameRecords( ) } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface stackFrameLogicValues { + stackFrameRecords: KeyedStackFrameRecords + stackFrameRecordsLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface stackFrameLogicActions { + loadForSymbolSet: (symbolSetId: ErrorTrackingSymbolSet['id']) => { + symbolSetId: string + } + loadForSymbolSetFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadForSymbolSetSuccess: ( + stackFrameRecords: KeyedStackFrameRecords, + payload?: { + symbolSetId: string + } + ) => { + stackFrameRecords: KeyedStackFrameRecords + payload?: { + symbolSetId: string + } + } + loadFromRawIds: (rawIds: ErrorTrackingStackFrame['raw_id'][]) => { + rawIds: string[] + } + loadFromRawIdsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadFromRawIdsSuccess: ( + stackFrameRecords: KeyedStackFrameRecords, + payload?: { + rawIds: string[] + } + ) => { + stackFrameRecords: KeyedStackFrameRecords + payload?: { + rawIds: string[] + } + } +} + +export type stackFrameLogicType = MakeLogicType + export const stackFrameLogic = kea([ path(['components', 'Errors', 'stackFrameLogic']), diff --git a/frontend/src/lib/components/Errors/errorPropertiesLogic.ts b/frontend/src/lib/components/Errors/errorPropertiesLogic.ts index 2bffd49a619b..5a13cf079f39 100644 --- a/frontend/src/lib/components/Errors/errorPropertiesLogic.ts +++ b/frontend/src/lib/components/Errors/errorPropertiesLogic.ts @@ -1,4 +1,4 @@ -import { connect, kea, key, path, props, selectors } from 'kea' +import { MakeLogicType, connect, kea, key, path, props, selectors } from 'kea' import { subscriptions } from 'kea-subscriptions' import { @@ -20,14 +20,80 @@ import { import { dayjs } from 'lib/dayjs' import { preflightLogic } from 'lib/logic/preflightLogic' -import type { errorPropertiesLogicType } from './errorPropertiesLogicType' import { KeyedStackFrameRecords, stackFrameLogic } from './Frame/stackFrameLogic' +import type { ExceptionAttributes } from './types' export interface ErrorPropertiesLogicProps { properties?: ErrorEventProperties id: ErrorEventId } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface errorPropertiesLogicValues { + isCloudOrDev: boolean | undefined // preflightLogic + stackFrameRecords: KeyedStackFrameRecords // stackFrameLogic + stackFrameRecordsLoading: boolean // stackFrameLogic + additionalProperties: Record + exceptionAttributes: ExceptionAttributes | null + exceptionList: ErrorTrackingException[] + exceptionType: string | null + fingerprintRecords: FingerprintRecordPart[] + frames: ErrorTrackingStackFrame[] + getExceptionFingerprint: (excId: string) => FingerprintRecordPart | undefined + getFrameFingerprint: (frameRawId: string) => FingerprintRecordPart | undefined + hasStacktrace: boolean + properties: Record + recordingStatus: string | undefined + release: ErrorTrackingRelease | null | undefined + sessionId: string | undefined + uuid: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface errorPropertiesLogicActions { + loadFromRawIds: (rawIds: string[]) => { + rawIds: string[] + } // stackFrameLogic +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface errorPropertiesLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + properties: (arg: ErrorEventProperties) => Record + exceptionAttributes: (properties: Record) => ExceptionAttributes | null + exceptionList: (properties: Record) => ErrorTrackingException[] + exceptionType: (exceptionList: ErrorTrackingException[]) => string | null + additionalProperties: ( + properties: Record, + isCloudOrDev: boolean | undefined + ) => Record + fingerprintRecords: (properties: Record) => FingerprintRecordPart[] + hasStacktrace: (exceptionList: ErrorTrackingException[]) => boolean + sessionId: (properties: Record) => string | undefined + recordingStatus: (properties: Record) => string | undefined + getExceptionFingerprint: ( + fingerprintRecords: FingerprintRecordPart[] + ) => (excId: string) => FingerprintRecordPart | undefined + getFrameFingerprint: ( + fingerprintRecords: FingerprintRecordPart[] + ) => (frameRawId: string) => FingerprintRecordPart | undefined + frames: (exceptionList: ErrorTrackingException[]) => ErrorTrackingStackFrame[] + uuid: (id: string) => string + release: ( + frames: ErrorTrackingStackFrame[], + stackFrameRecords: KeyedStackFrameRecords + ) => ErrorTrackingRelease | null | undefined + } +} + +export type errorPropertiesLogicType = MakeLogicType< + errorPropertiesLogicValues, + errorPropertiesLogicActions, + ErrorPropertiesLogicProps, + errorPropertiesLogicMeta +> + export const errorPropertiesLogic = kea([ path((key) => ['components', 'Errors', 'errorPropertiesLogic', key]), props({} as ErrorPropertiesLogicProps), diff --git a/frontend/src/lib/components/EventPropertyTabs/eventPropertyFilteringLogic.ts b/frontend/src/lib/components/EventPropertyTabs/eventPropertyFilteringLogic.ts index c79328e7fcaa..29717a7a1baf 100644 --- a/frontend/src/lib/components/EventPropertyTabs/eventPropertyFilteringLogic.ts +++ b/frontend/src/lib/components/EventPropertyTabs/eventPropertyFilteringLogic.ts @@ -1,11 +1,33 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { preflightLogic } from 'lib/logic/preflightLogic' import { userPreferencesLogic } from 'lib/logic/userPreferencesLogic' import { CLOUD_INTERNAL_POSTHOG_PROPERTY_KEYS, PROPERTY_KEYS } from '~/taxonomy/taxonomy' -import type { eventPropertyFilteringLogicType } from './eventPropertyFilteringLogicType' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface eventPropertyFilteringLogicValues { + isCloudOrDev: boolean | undefined // preflightLogic + hidePostHogPropertiesInTable: boolean // userPreferencesLogic + filterProperties: (props: Record) => Record +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface eventPropertyFilteringLogicMeta { + __keaTypeGenInternalSelectorTypes: { + filterProperties: ( + hidePostHogPropertiesInTable: boolean, + isCloudOrDev: boolean | undefined + ) => (props: Record) => Record + } +} + +export type eventPropertyFilteringLogicType = MakeLogicType< + eventPropertyFilteringLogicValues, + {}, + Record, + eventPropertyFilteringLogicMeta +> export const eventPropertyFilteringLogic = kea([ path(['lib', 'components', 'EventPropertyTabs', 'eventPropertyFilteringLogic']), @@ -15,7 +37,7 @@ export const eventPropertyFilteringLogic = kea( selectors({ filterProperties: [ (s) => [s.hidePostHogPropertiesInTable, s.isCloudOrDev], - (hidePostHogPropertiesInTable, isCloudOrDev) => { + (hidePostHogPropertiesInTable: boolean, isCloudOrDev: boolean | undefined) => { return (props: Record) => { if (!hidePostHogPropertiesInTable) { return props diff --git a/frontend/src/lib/components/ExportButton/exportsLogic.ts b/frontend/src/lib/components/ExportButton/exportsLogic.ts index 03e8a9e93dab..f55bc329987f 100644 --- a/frontend/src/lib/components/ExportButton/exportsLogic.ts +++ b/frontend/src/lib/components/ExportButton/exportsLogic.ts @@ -1,4 +1,4 @@ -import { actions, kea, listeners, path, reducers } from 'kea' +import { MakeLogicType, actions, kea, listeners, path, reducers } from 'kea' import { loaders } from 'kea-loaders' import { router } from 'kea-router' @@ -16,8 +16,6 @@ import { cohortsModel } from '~/models/cohortsModel' import { AnyDataNode } from '~/queries/schema/schema-general' import { APIErrorType, CohortType, ExportContext, ExportedAssetType, ExporterFormat, LocalExportContext } from '~/types' -import type { exportsLogicType } from './exportsLogicType' - const POLL_DELAY_MS = 10000 // Long-running formats (e.g. MP4 session-replay renders) can take 30+ minutes, // so polling every 10s produces unhelpful timeout noise. Back off when the @@ -37,6 +35,119 @@ export const pickPollDelayMs = (pendingAssets: ExportedAssetType[]): number => { const isLocalExport = (context: ExportContext | undefined): context is LocalExportContext => !!(context && 'localData' in context) +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface exportsLogicValues { + assetFormat: ExporterFormat | null + exports: ExportedAssetType[] + exportsLoading: boolean + freshUndownloadedExports: ExportedAssetType[] + hasReachedExportFullVideoLimit: boolean + pollingExports: ExportedAssetType[] + pollingExportsLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface exportsLogicActions { + addFresh: (exportedAsset: ExportedAssetType) => { + exportedAsset: ExportedAssetType + } + checkExportStatus: (exportedAsset: ExportedAssetType) => { + exportedAsset: ExportedAssetType + } + createExport: ({ exportData }: any) => any + createExportFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + createExportSuccess: ( + pollingExports: any[], + payload?: any + ) => { + pollingExports: any[] + payload?: any + } + createStaticCohort: ( + name: string, + query: AnyDataNode + ) => { + name: string + query: AnyDataNode + } + loadExports: () => { + value: true + } + loadExportsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadExportsSuccess: ( + exports: ExportedAssetType[], + payload?: { + value: true + } + ) => { + exports: ExportedAssetType[] + payload?: { + value: true + } + } + pollExportStatus: (exportedAsset: ExportedAssetType) => { + exportedAsset: ExportedAssetType + } + removeFresh: (exportedAsset: ExportedAssetType) => { + exportedAsset: ExportedAssetType + } + setAssetFormat: (format: ExporterFormat | null) => { + format: ExporterFormat | null + } + setHasReachedExportFullVideoLimit: (hasReached: boolean) => { + hasReached: boolean + } + startExport: (exportData: TriggerExportProps) => { + exportData: TriggerExportProps + } + startHeatmapExport: (export_context: ExportContext) => { + export_context: ExportContext + } + startReplayExport: ( + sessionRecordingId: string, + format?: ExporterFormat, + timestamp?: number, + duration?: number, + mode?: SessionRecordingPlayerMode, + options?: { + css_selector?: string + filename?: string + height?: number + skip_inactivity?: boolean + width?: number + } + ) => { + duration: number | undefined + format: ExporterFormat | undefined + mode: SessionRecordingPlayerMode | undefined + options: + | { + css_selector?: string | undefined + filename?: string | undefined + height?: number | undefined + skip_inactivity?: boolean | undefined + width?: number | undefined + } + | undefined + sessionRecordingId: string + timestamp: number | undefined + } +} + +export type exportsLogicType = MakeLogicType + export const exportsLogic = kea([ path(['scenes', 'navigation', 'sidepanel', 'exportsLogic']), diff --git a/frontend/src/lib/components/FileSystem/ItemSelectModal/itemSelectModalLogic.tsx b/frontend/src/lib/components/FileSystem/ItemSelectModal/itemSelectModalLogic.tsx index c304d4aa8a32..221128304bd5 100644 --- a/frontend/src/lib/components/FileSystem/ItemSelectModal/itemSelectModalLogic.tsx +++ b/frontend/src/lib/components/FileSystem/ItemSelectModal/itemSelectModalLogic.tsx @@ -1,5 +1,6 @@ -import { actions, connect, kea, path, reducers } from 'kea' +import { MakeLogicType, actions, connect, kea, path, reducers } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { lemonToast } from '@posthog/lemon-ui' @@ -10,7 +11,100 @@ import { projectTreeDataLogic } from '~/layout/panel-layout/ProjectTree/projectT import { joinPath, splitPath } from '~/layout/panel-layout/ProjectTree/utils' import { FileSystemEntry } from '~/queries/schema/schema-general' -import type { itemSelectModalLogicType } from './itemSelectModalLogicType' +import type { FeatureFlagsSet } from '../../../logic/featureFlagLogic' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface itemSelectModalLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + shortcutData: FileSystemEntry[] // projectTreeDataLogic + form: { + item: TreeDataItem | null + } + formAllErrors: Record + formChanged: boolean + formErrors: DeepPartialMap< + { + item: TreeDataItem | null + }, + ValidationErrorType + > + formHasErrors: boolean + formManualErrors: Record + formTouched: boolean + formTouches: Record + formValidationErrors: DeepPartialMap< + { + item: TreeDataItem | null + }, + ValidationErrorType + > + isFormSubmitting: boolean + isFormValid: boolean + isOpen: boolean + showFormErrors: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface itemSelectModalLogicActions { + addShortcutItem: (item: FileSystemEntry) => { + item: FileSystemEntry + } // projectTreeDataLogic + closeItemSelectModal: () => { + value: true + } + openItemSelectModal: () => { + value: true + } + resetForm: (values?: { item: TreeDataItem | null }) => { + values?: { + item: TreeDataItem | null + } + } + setFormManualErrors: (errors: Record) => { + errors: Record + } + setFormValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setFormValues: ( + values: DeepPartial<{ + item: TreeDataItem | null + }> + ) => { + values: DeepPartial<{ + item: TreeDataItem | null + }> + } + submitForm: () => { + value: boolean + } + submitFormFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitFormRequest: (form: { item: TreeDataItem | null }) => { + form: { + item: TreeDataItem | null + } + } + submitFormSuccess: (form: { item: TreeDataItem | null }) => { + form: { + item: TreeDataItem | null + } + } + touchFormField: (key: string) => { + key: string + } +} + +export type itemSelectModalLogicType = MakeLogicType export const itemSelectModalLogic = kea([ path(['lib', 'components', 'FileSystem', 'ItemSelectModal', 'itemSelectModalLogic']), diff --git a/frontend/src/lib/components/FileSystem/LinkTo/linkToLogic.tsx b/frontend/src/lib/components/FileSystem/LinkTo/linkToLogic.tsx index 870f213a011d..b0e63cb7550c 100644 --- a/frontend/src/lib/components/FileSystem/LinkTo/linkToLogic.tsx +++ b/frontend/src/lib/components/FileSystem/LinkTo/linkToLogic.tsx @@ -1,5 +1,6 @@ -import { actions, connect, kea, listeners, path, reducers } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' @@ -9,7 +10,118 @@ import { projectTreeLogic } from '~/layout/panel-layout/ProjectTree/projectTreeL import { calculateMovePath, joinPath, splitPath } from '~/layout/panel-layout/ProjectTree/utils' import { FileSystemEntry } from '~/queries/schema/schema-general' -import type { linkToLogicType } from './linkToLogicType' +import type { ProjectTreeRef } from '../../../../types' +import type { FeatureFlagsSet } from '../../../logic/featureFlagLogic' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface linkToLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + lastNewFolder: string | null // projectTreeDataLogic + projectTreeRef: ProjectTreeRef | null // projectTreeDataLogic + projectTreeRefEntry: FileSystemEntry | null // projectTreeDataLogic + form: { + folder: string | null + } + formAllErrors: Record + formChanged: boolean + formErrors: DeepPartialMap< + { + folder: string | null + }, + ValidationErrorType + > + formHasErrors: boolean + formManualErrors: Record + formTouched: boolean + formTouches: Record + formValidationErrors: DeepPartialMap< + { + folder: string | null + }, + ValidationErrorType + > + isFormSubmitting: boolean + isFormValid: boolean + isOpen: boolean + linkingItems: FileSystemEntry[] + showFormErrors: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface linkToLogicActions { + linkItem: ( + oldPath: string, + newPath: string, + force: boolean, + projectTreeLogicKey: string + ) => { + force: boolean + newPath: string + oldPath: string + projectTreeLogicKey: string + } // projectTreeDataLogic + setLastNewFolder: (folder: string | null) => { + folder: string | null + } // projectTreeDataLogic + closeLinkToModal: () => { + value: true + } + closedLinkToModal: () => { + value: true + } + openLinkToModal: (items: FileSystemEntry[]) => { + items: FileSystemEntry[] + } + resetForm: (values?: { folder: string | null }) => { + values?: { + folder: string | null + } + } + setFormManualErrors: (errors: Record) => { + errors: Record + } + setFormValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setFormValues: ( + values: DeepPartial<{ + folder: string | null + }> + ) => { + values: DeepPartial<{ + folder: string | null + }> + } + submitForm: () => { + value: boolean + } + submitFormFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitFormRequest: (form: { folder: string | null }) => { + form: { + folder: string | null + } + } + submitFormSuccess: (form: { folder: string | null }) => { + form: { + folder: string | null + } + } + touchFormField: (key: string) => { + key: string + } +} + +export type linkToLogicType = MakeLogicType export const linkToLogic = kea([ path(['lib', 'components', 'LinkTo', 'linkToLogic']), diff --git a/frontend/src/lib/components/FileSystem/MoveTo/moveToLogic.tsx b/frontend/src/lib/components/FileSystem/MoveTo/moveToLogic.tsx index 19029cc4ddc9..f8b3bf788671 100644 --- a/frontend/src/lib/components/FileSystem/MoveTo/moveToLogic.tsx +++ b/frontend/src/lib/components/FileSystem/MoveTo/moveToLogic.tsx @@ -1,5 +1,6 @@ -import { actions, connect, kea, listeners, path, reducers } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' @@ -9,7 +10,118 @@ import { projectTreeLogic } from '~/layout/panel-layout/ProjectTree/projectTreeL import { calculateMovePath, joinPath, splitPath } from '~/layout/panel-layout/ProjectTree/utils' import { FileSystemEntry } from '~/queries/schema/schema-general' -import type { moveToLogicType } from './moveToLogicType' +import type { ProjectTreeRef } from '../../../../types' +import type { FeatureFlagsSet } from '../../../logic/featureFlagLogic' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface moveToLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + lastNewFolder: string | null // projectTreeDataLogic + projectTreeRef: ProjectTreeRef | null // projectTreeDataLogic + projectTreeRefEntry: FileSystemEntry | null // projectTreeDataLogic + form: { + folder: string | null + } + formAllErrors: Record + formChanged: boolean + formErrors: DeepPartialMap< + { + folder: string | null + }, + ValidationErrorType + > + formHasErrors: boolean + formManualErrors: Record + formTouched: boolean + formTouches: Record + formValidationErrors: DeepPartialMap< + { + folder: string | null + }, + ValidationErrorType + > + isFormSubmitting: boolean + isFormValid: boolean + isOpen: boolean + movingItems: FileSystemEntry[] + showFormErrors: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface moveToLogicActions { + moveItem: ( + item: FileSystemEntry, + newPath: string, + force: boolean, + projectTreeLogicKey: string + ) => { + force: boolean + item: FileSystemEntry + newPath: string + projectTreeLogicKey: string + } // projectTreeDataLogic + setLastNewFolder: (folder: string | null) => { + folder: string | null + } // projectTreeDataLogic + closeMoveToModal: () => { + value: true + } + closedMoveToModal: () => { + value: true + } + openMoveToModal: (items: FileSystemEntry[]) => { + items: FileSystemEntry[] + } + resetForm: (values?: { folder: string | null }) => { + values?: { + folder: string | null + } + } + setFormManualErrors: (errors: Record) => { + errors: Record + } + setFormValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setFormValues: ( + values: DeepPartial<{ + folder: string | null + }> + ) => { + values: DeepPartial<{ + folder: string | null + }> + } + submitForm: () => { + value: boolean + } + submitFormFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitFormRequest: (form: { folder: string | null }) => { + form: { + folder: string | null + } + } + submitFormSuccess: (form: { folder: string | null }) => { + form: { + folder: string | null + } + } + touchFormField: (key: string) => { + key: string + } +} + +export type moveToLogicType = MakeLogicType export const moveToLogic = kea([ path(['lib', 'components', 'MoveTo', 'moveToLogic']), diff --git a/frontend/src/lib/components/HTMLElementsDisplay/htmlElementsDisplayLogic.ts b/frontend/src/lib/components/HTMLElementsDisplay/htmlElementsDisplayLogic.ts index 5318d3689016..2b600957ef79 100644 --- a/frontend/src/lib/components/HTMLElementsDisplay/htmlElementsDisplayLogic.ts +++ b/frontend/src/lib/components/HTMLElementsDisplay/htmlElementsDisplayLogic.ts @@ -1,4 +1,4 @@ -import { actions, kea, key, path, props, propsChanged, reducers, selectors } from 'kea' +import { MakeLogicType, actions, kea, key, path, props, propsChanged, reducers, selectors } from 'kea' import { subscriptions } from 'kea-subscriptions' import { @@ -10,8 +10,6 @@ import { objectsEqual } from 'lib/utils/objects' import { ElementType } from '~/types' -import type { htmlElementsDisplayLogicType } from './htmlElementsDisplayLogicType' - export interface HtmlElementDisplayLogicProps { checkUniqueness: boolean onChange?: (selector: string, isUnique?: boolean) => void @@ -25,6 +23,56 @@ export const elementsChain = (providedElements: ElementType[] | undefined): Elem return safeElements.reverse() } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface htmlElementsDisplayLogicValues { + chosenSelector: string + chosenSelectorMatchCount: number | null + elements: ElementType[] + elementsToShowDepth: number + messageStatus: 'info' | 'success' | 'warning' + parsedElements: ElementType[] + parsedSelectors: Record + parsedSelectorsRaw: Record + visibleElements: number +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface htmlElementsDisplayLogicActions { + setElements: (providedElements: ElementType[]) => { + providedElements: ElementType[] + } + setParsedSelectors: (selectors: Record) => { + selectors: Record + } + showAdditionalElements: () => { + value: true + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface htmlElementsDisplayLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + parsedSelectors: ( + parsedSelectorsRaw: Record, + arg: any, + elements: ElementType[] + ) => Record + parsedElements: (elements: ElementType[], visibleElements: number) => ElementType[] + elementsToShowDepth: (elements: ElementType[], visibleElements: number) => number + chosenSelector: (parsedSelectors: Record) => string + chosenSelectorMatchCount: (chosenSelector: string, arg: any) => number | null + messageStatus: (chosenSelectorMatchCount: number | null) => 'info' | 'success' | 'warning' + } +} + +export type htmlElementsDisplayLogicType = MakeLogicType< + htmlElementsDisplayLogicValues, + htmlElementsDisplayLogicActions, + HtmlElementDisplayLogicProps, + htmlElementsDisplayLogicMeta +> + export const htmlElementsDisplayLogic = kea([ path(['lib', 'components', 'HtmlElementsDisplay', 'htmlElementsDisplayLogic']), props({ checkUniqueness: true } as HtmlElementDisplayLogicProps), @@ -54,14 +102,18 @@ export const htmlElementsDisplayLogic = kea([ // each element in the chain has a parsed selector it uses to track which things are selected parsedSelectors: [ (s) => [s.parsedSelectorsRaw, (_, props) => props.startingSelector, s.elements], - (parsedSelectorsRaw, startingSelector, providedElements): Record => + ( + parsedSelectorsRaw: Record, + startingSelector, + providedElements: ElementType[] + ): Record => startingSelector && Object.keys(parsedSelectorsRaw).length === 0 ? preselect(providedElements, startingSelector) : parsedSelectorsRaw, ], parsedElements: [ (s) => [s.elements, s.visibleElements], - (elements, visibleElements) => { + (elements: ElementType[], visibleElements: number) => { return elements.slice(Math.max(elements.length - visibleElements, 0)) }, ], @@ -74,7 +126,7 @@ export const htmlElementsDisplayLogic = kea([ // contains the selector string built from the parsed selectors chosenSelector: [ (s) => [s.parsedSelectors], - (parsedSelectors): string => { + (parsedSelectors: Record): string => { let lastKey = -2 let builtSelector = '' @@ -102,7 +154,7 @@ export const htmlElementsDisplayLogic = kea([ ], chosenSelectorMatchCount: [ (s) => [s.chosenSelector, (_, props) => props.checkUniqueness], - (chosenSelector, checkUniqueness): number | null => { + (chosenSelector: string, checkUniqueness): number | null => { let selectorMatchCount: number | null = null if (checkUniqueness && chosenSelector !== 'no selectors chosen') { try { @@ -117,7 +169,7 @@ export const htmlElementsDisplayLogic = kea([ ], messageStatus: [ (s) => [s.chosenSelectorMatchCount], - (chosenSelectorMatchCount) => { + (chosenSelectorMatchCount: number | null) => { return chosenSelectorMatchCount === null ? 'info' : chosenSelectorMatchCount === 1 diff --git a/frontend/src/lib/components/HedgehogMode/hedgehogModeLogic.ts b/frontend/src/lib/components/HedgehogMode/hedgehogModeLogic.ts index 7316a94960db..6a6d02a99903 100644 --- a/frontend/src/lib/components/HedgehogMode/hedgehogModeLogic.ts +++ b/frontend/src/lib/components/HedgehogMode/hedgehogModeLogic.ts @@ -1,4 +1,15 @@ -import { actions, afterMount, beforeUnmount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { + MakeLogicType, + actions, + afterMount, + beforeUnmount, + connect, + kea, + listeners, + path, + reducers, + selectors, +} from 'kea' import { loaders } from 'kea-loaders' import { subscriptions } from 'kea-subscriptions' import posthog from 'posthog-js' @@ -11,10 +22,106 @@ import { toolbarConfigLogic } from '~/toolbar/toolbarConfigLogic' import { toolbarFetch } from '~/toolbar/toolbarFetch' import { HedgehogConfig, MinimalHedgehogConfig } from '~/types' +import type { OrganizationMemberType, UserType } from '../../../types' import { sanitizeHedgehogConfig } from './hedgehog-mode-utils' -import type { hedgehogModeLogicType } from './hedgehogModeLogicType' import { HedgehogModeInterface } from './types' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface hedgehogModeLogicValues { + members: OrganizationMemberType[] | null // membersLogic + user: UserType | null // userLogic + hedgehogConfig: HedgehogConfig + hedgehogMode: HedgehogModeInterface | null + hedgehogModeEnabled: boolean + minimalHedgehogConfig: MinimalHedgehogConfig + remoteConfig: Partial | null + remoteConfigLoading: boolean + remoteConfigUpdateDisabled: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface hedgehogModeLogicActions { + ensureAllMembersLoaded: () => { + value: true + } // membersLogic + loadRemoteConfig: () => { + value: true + } + loadRemoteConfigFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadRemoteConfigSuccess: ( + remoteConfig: Partial | null, + payload?: { + value: true + } + ) => { + remoteConfig: Partial | null + payload?: { + value: true + } + } + setHedgehogMode: (hedgeHogMode: HedgehogModeInterface) => { + hedgeHogMode: HedgehogModeInterface + } + setHedgehogModeEnabled: (enabled: boolean) => { + enabled: boolean + } + setRemoteConfigUpdateDisabled: (disabled: boolean) => { + disabled: boolean + } + syncFromState: () => { + value: true + } + syncGame: () => { + value: true + } + toggleHedgehogMode: () => { + value: true + } + updateRemoteConfig: (config: Partial) => { + config: Partial + } + updateRemoteConfigFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + updateRemoteConfigSuccess: ( + remoteConfig: Partial | null, + payload?: { + config: Partial + } + ) => { + remoteConfig: Partial | null + payload?: { + config: Partial + } + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface hedgehogModeLogicMeta { + __keaTypeGenInternalSelectorTypes: { + hedgehogConfig: (remoteConfig: Partial | null) => HedgehogConfig + hedgehogModeEnabled: (hedgehogConfig: HedgehogConfig) => boolean + minimalHedgehogConfig: (hedgehogConfig: HedgehogConfig) => MinimalHedgehogConfig + } +} + +export type hedgehogModeLogicType = MakeLogicType< + hedgehogModeLogicValues, + hedgehogModeLogicActions, + Record, + hedgehogModeLogicMeta +> + export const hedgehogModeLogic = kea([ path(['hedgehog', 'hedgehogModeLogic']), connect({ @@ -106,7 +213,7 @@ export const hedgehogModeLogic = kea([ selectors({ hedgehogConfig: [ (s) => [s.remoteConfig], - (remoteConfig): HedgehogConfig => { + (remoteConfig: Partial | null): HedgehogConfig => { return sanitizeHedgehogConfig({ ...remoteConfig, }) @@ -115,14 +222,14 @@ export const hedgehogModeLogic = kea([ hedgehogModeEnabled: [ (s) => [s.hedgehogConfig], - (hedgehogConfig): boolean => { + (hedgehogConfig: HedgehogConfig): boolean => { return !!hedgehogConfig.enabled }, ], minimalHedgehogConfig: [ (s) => [s.hedgehogConfig], - (hedgehogConfig): MinimalHedgehogConfig => { + (hedgehogConfig: HedgehogConfig): MinimalHedgehogConfig => { const forcedHedeghogProfile: MinimalHedgehogConfig = { use_as_profile: true, color: hedgehogConfig?.actor_options?.color, diff --git a/frontend/src/lib/components/HelpMenu/healthSummaryLogic.tsx b/frontend/src/lib/components/HelpMenu/healthSummaryLogic.tsx index ea9b0b08523b..dfc4ebb14f11 100644 --- a/frontend/src/lib/components/HelpMenu/healthSummaryLogic.tsx +++ b/frontend/src/lib/components/HelpMenu/healthSummaryLogic.tsx @@ -1,14 +1,57 @@ -import { afterMount, connect, kea, listeners, path, selectors } from 'kea' +import { MakeLogicType, afterMount, connect, kea, listeners, path, selectors } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' import type { HealthIssueSummary } from 'scenes/health/types' import { teamLogic } from 'scenes/teamLogic' -import type { healthSummaryLogicType } from './healthSummaryLogicType' - const REFRESH_INTERVAL = 60 * 1000 * 5 +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface healthSummaryLogicValues { + currentTeamIdStrict: number | string // teamLogic + criticalCount: number + healthSummary: HealthIssueSummary | null + healthSummaryLoading: boolean + totalIssues: number + warningCount: number +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface healthSummaryLogicActions { + loadHealthSummary: () => any + loadHealthSummaryFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadHealthSummarySuccess: ( + healthSummary: HealthIssueSummary | null, + payload?: any + ) => { + healthSummary: HealthIssueSummary | null + payload?: any + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface healthSummaryLogicMeta { + __keaTypeGenInternalSelectorTypes: { + totalIssues: (healthSummary: HealthIssueSummary | null) => number + criticalCount: (healthSummary: HealthIssueSummary | null) => number + warningCount: (healthSummary: HealthIssueSummary | null) => number + } +} + +export type healthSummaryLogicType = MakeLogicType< + healthSummaryLogicValues, + healthSummaryLogicActions, + Record, + healthSummaryLogicMeta +> + export const healthSummaryLogic = kea([ path(['lib', 'components', 'HelpMenu', 'healthSummaryLogic']), connect(() => ({ values: [teamLogic, ['currentTeamIdStrict']] })), diff --git a/frontend/src/lib/components/HelpMenu/helpMenuLogic.tsx b/frontend/src/lib/components/HelpMenu/helpMenuLogic.tsx index fef45ffea20f..6d963899e8fb 100644 --- a/frontend/src/lib/components/HelpMenu/helpMenuLogic.tsx +++ b/frontend/src/lib/components/HelpMenu/helpMenuLogic.tsx @@ -1,10 +1,46 @@ -import { actions, connect, kea, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, path, reducers, selectors } from 'kea' import { healthSummaryLogic } from './healthSummaryLogic' -import type { helpMenuLogicType } from './helpMenuLogicType' export type HelpBadgeStatus = 'danger' | 'warning' | 'success' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface helpMenuLogicValues { + criticalCount: number // healthSummaryLogic + totalIssues: number // healthSummaryLogic + warningCount: number // healthSummaryLogic + hasHealthIssue: boolean + isHelpMenuOpen: boolean + triggerBadgeContent: string + triggerBadgeStatus: HelpBadgeStatus +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface helpMenuLogicActions { + setHelpMenuOpen: (isOpen: boolean) => { + isOpen: boolean + } + toggleHelpMenu: () => { + value: true + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface helpMenuLogicMeta { + __keaTypeGenInternalSelectorTypes: { + hasHealthIssue: (totalIssues: number) => boolean + triggerBadgeContent: (hasHealthIssue: boolean) => string + triggerBadgeStatus: (hasHealthIssue: boolean, criticalCount: number, warningCount: number) => HelpBadgeStatus + } +} + +export type helpMenuLogicType = MakeLogicType< + helpMenuLogicValues, + helpMenuLogicActions, + Record, + helpMenuLogicMeta +> + export const helpMenuLogic = kea([ path(['lib', 'components', 'HelpMenu', 'helpMenuLogic']), connect(() => ({ @@ -24,11 +60,14 @@ export const helpMenuLogic = kea([ ], }), selectors({ - hasHealthIssue: [(s) => [s.totalIssues], (totalIssues): boolean => totalIssues > 0], - triggerBadgeContent: [(s) => [s.hasHealthIssue], (hasHealthIssue): string => (hasHealthIssue ? '!' : '')], + hasHealthIssue: [(s) => [s.totalIssues], (totalIssues: number): boolean => totalIssues > 0], + triggerBadgeContent: [ + (s) => [s.hasHealthIssue], + (hasHealthIssue: boolean): string => (hasHealthIssue ? '!' : ''), + ], triggerBadgeStatus: [ (s) => [s.hasHealthIssue, s.criticalCount, s.warningCount], - (hasHealthIssue, criticalCount, warningCount): HelpBadgeStatus => { + (hasHealthIssue: boolean, criticalCount: number, warningCount: number): HelpBadgeStatus => { if (!hasHealthIssue) { return 'success' } diff --git a/frontend/src/lib/components/HelpMenu/incidentStatusLogic.tsx b/frontend/src/lib/components/HelpMenu/incidentStatusLogic.tsx index 3956efbb17ae..d8ccc5707c99 100644 --- a/frontend/src/lib/components/HelpMenu/incidentStatusLogic.tsx +++ b/frontend/src/lib/components/HelpMenu/incidentStatusLogic.tsx @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, selectors } from 'kea' import { loaders } from 'kea-loaders' import posthog from 'posthog-js' @@ -8,8 +8,9 @@ import { preflightLogic } from 'lib/logic/preflightLogic' import { Region } from '~/types' +import type { PreflightStatus } from '../../../types' +import type { FakeStatusOverride } from '../Superpowers/superpowersLogic' import { NormalizedStatus, STATUS_PAGE_BASE, setIncidentStatus } from './incidentStatus' -import type { incidentStatusLogicType } from './incidentStatusLogicType' // Raw status page API types export type ComponentStatus = 'operational' | 'degraded_performance' | 'partial_outage' | 'full_outage' @@ -206,6 +207,69 @@ function getAiIncidentAlerts(summary: Summary | null, relevantGroupName: string }, []) } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface incidentStatusLogicValues { + preflight: PreflightStatus | null // preflightLogic + fakeStatusOverride: FakeStatusOverride // superpowersLogic + superpowersEnabled: boolean | undefined // superpowersLogic + aiIncidentAlerts: ComponentIncidentAlert[] + rawStatus: NormalizedStatus + relevantGroupName: string | null + status: NormalizedStatus + statusDescription: string | null + statusPageUrl: string + summary: Summary | null + summaryLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface incidentStatusLogicActions { + loadSummary: () => any + loadSummaryFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadSummarySuccess: ( + summary: Summary | null, + payload?: any + ) => { + summary: Summary | null + payload?: any + } + setPageVisibility: (visible: boolean) => { + visible: boolean + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface incidentStatusLogicMeta { + __keaTypeGenInternalSelectorTypes: { + relevantGroupName: (preflight: PreflightStatus | null) => string | null + rawStatus: (summary: Summary | null, relevantGroupName: string | null) => NormalizedStatus + status: ( + rawStatus: NormalizedStatus, + fakeStatusOverride: FakeStatusOverride, + superpowersEnabled: boolean | undefined + ) => NormalizedStatus + aiIncidentAlerts: (summary: Summary | null, relevantGroupName: string | null) => ComponentIncidentAlert[] + statusDescription: ( + summary: Summary | null, + status: NormalizedStatus, + relevantGroupName: string | null + ) => string | null + } +} + +export type incidentStatusLogicType = MakeLogicType< + incidentStatusLogicValues, + incidentStatusLogicActions, + Record, + incidentStatusLogicMeta +> + export const incidentStatusLogic = kea([ path(['lib', 'components', 'HelpMenu', 'incidentStatusLogic']), @@ -254,11 +318,12 @@ export const incidentStatusLogic = kea([ statusPageUrl: [() => [], (): string => getStatusPageUrl()], relevantGroupName: [ (s) => [s.preflight], - (preflight): string | null => getRelevantGroupName(preflight?.region), + (preflight: null | import('~/types').PreflightStatus): string | null => + getRelevantGroupName(preflight?.region), ], rawStatus: [ (s) => [s.summary, s.relevantGroupName], - (summary: Summary | null, relevantGroupName): NormalizedStatus => { + (summary: Summary | null, relevantGroupName: string | null): NormalizedStatus => { if (!summary) { return 'operational' } @@ -267,7 +332,11 @@ export const incidentStatusLogic = kea([ ], status: [ (s) => [s.rawStatus, s.fakeStatusOverride, s.superpowersEnabled], - (rawStatus, fakeStatusOverride, superpowersEnabled): NormalizedStatus => { + ( + rawStatus: NormalizedStatus, + fakeStatusOverride: import('lib/components/Superpowers/superpowersLogic').FakeStatusOverride, + superpowersEnabled: boolean | undefined + ): NormalizedStatus => { if (superpowersEnabled && fakeStatusOverride !== 'none') { return fakeStatusOverride as NormalizedStatus } @@ -276,12 +345,12 @@ export const incidentStatusLogic = kea([ ], aiIncidentAlerts: [ (s) => [s.summary, s.relevantGroupName], - (summary: Summary | null, relevantGroupName): ComponentIncidentAlert[] => + (summary: Summary | null, relevantGroupName: string | null): ComponentIncidentAlert[] => getAiIncidentAlerts(summary, relevantGroupName), ], statusDescription: [ (s) => [s.summary, s.status, s.relevantGroupName], - (summary, status, relevantGroupName): string | null => { + (summary: Summary | null, status: NormalizedStatus, relevantGroupName: string | null): string | null => { if (!summary) { return null } diff --git a/frontend/src/lib/components/HelpMenu/posthogStatusLogic.tsx b/frontend/src/lib/components/HelpMenu/posthogStatusLogic.tsx index 581f41c9ea4e..34889c496476 100644 --- a/frontend/src/lib/components/HelpMenu/posthogStatusLogic.tsx +++ b/frontend/src/lib/components/HelpMenu/posthogStatusLogic.tsx @@ -1,14 +1,51 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { superpowersLogic } from 'lib/components/Superpowers/superpowersLogic' import { capitalizeFirstLetter } from 'lib/utils/strings' +import type { FakeStatusOverride } from '../Superpowers/superpowersLogic' +import type { NormalizedStatus } from './incidentStatus' import { incidentStatusLogic } from './incidentStatusLogic' -import type { posthogStatusLogicType } from './posthogStatusLogicType' export type PostHogStatusType = 'operational' | 'degraded_performance' | 'partial_outage' | 'major_outage' export type PostHogStatusBadgeStatus = 'success' | 'warning' | 'danger' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface posthogStatusLogicValues { + status: NormalizedStatus // incidentStatusLogic + statusDescription: string | null // incidentStatusLogic + statusPageUrl: string // incidentStatusLogic + fakeStatusOverride: FakeStatusOverride // superpowersLogic + superpowersEnabled: boolean | undefined // superpowersLogic + isFakeStatus: boolean + postHogStatus: PostHogStatusType + postHogStatusBadgeContent: string + postHogStatusBadgeStatus: PostHogStatusBadgeStatus + postHogStatusTooltip: string | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface posthogStatusLogicMeta { + __keaTypeGenInternalSelectorTypes: { + postHogStatus: (status: NormalizedStatus) => PostHogStatusType + isFakeStatus: (superpowersEnabled: boolean | undefined, fakeStatusOverride: FakeStatusOverride) => boolean + postHogStatusTooltip: ( + statusDescription: string | null, + isFakeStatus: boolean, + postHogStatus: PostHogStatusType + ) => string | null + postHogStatusBadgeContent: (postHogStatus: PostHogStatusType) => string + postHogStatusBadgeStatus: (postHogStatus: PostHogStatusType) => PostHogStatusBadgeStatus + } +} + +export type posthogStatusLogicType = MakeLogicType< + posthogStatusLogicValues, + {}, + Record, + posthogStatusLogicMeta +> + export const posthogStatusLogic = kea([ path(['lib', 'components', 'HelpMenu', 'posthogStatusLogic']), connect({ @@ -20,14 +57,24 @@ export const posthogStatusLogic = kea([ ], }), selectors({ - postHogStatus: [(s) => [s.status], (status): PostHogStatusType => status], + postHogStatus: [ + (s) => [s.status], + (status: import('./incidentStatus').NormalizedStatus): PostHogStatusType => status, + ], isFakeStatus: [ (s) => [s.superpowersEnabled, s.fakeStatusOverride], - (superpowersEnabled, fakeStatusOverride): boolean => !!superpowersEnabled && fakeStatusOverride !== 'none', + ( + superpowersEnabled: boolean | undefined, + fakeStatusOverride: import('lib/components/Superpowers/superpowersLogic').FakeStatusOverride + ): boolean => !!superpowersEnabled && fakeStatusOverride !== 'none', ], postHogStatusTooltip: [ (s) => [s.statusDescription, s.isFakeStatus, s.postHogStatus], - (statusDescription, isFakeStatus, postHogStatus): string | null => { + ( + statusDescription: string | null, + isFakeStatus: boolean, + postHogStatus: PostHogStatusType + ): string | null => { if (isFakeStatus) { return `[DRILL] ${capitalizeFirstLetter(postHogStatus.replace(/_/g, ' '))}` } @@ -36,11 +83,11 @@ export const posthogStatusLogic = kea([ ], postHogStatusBadgeContent: [ (s) => [s.postHogStatus], - (postHogStatus): string => (postHogStatus !== 'operational' ? '!' : '✓'), + (postHogStatus: PostHogStatusType): string => (postHogStatus !== 'operational' ? '!' : '✓'), ], postHogStatusBadgeStatus: [ (s) => [s.postHogStatus], - (postHogStatus): PostHogStatusBadgeStatus => { + (postHogStatus: PostHogStatusType): PostHogStatusBadgeStatus => { if (postHogStatus.includes('outage')) { return 'danger' } diff --git a/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts b/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts index 47f2dc258b35..1686f2d1b7cb 100644 --- a/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts +++ b/frontend/src/lib/components/IframedToolbarBrowser/iframedToolbarBrowserLogic.ts @@ -1,4 +1,16 @@ -import { actions, afterMount, beforeUnmount, connect, kea, listeners, path, props, reducers, selectors } from 'kea' +import { + MakeLogicType, + actions, + afterMount, + beforeUnmount, + connect, + kea, + listeners, + path, + props, + reducers, + selectors, +} from 'kea' import posthog from 'posthog-js' import { RefObject } from 'react' @@ -18,7 +30,9 @@ import { teamLogic } from 'scenes/teamLogic' import { ToolbarUserIntent } from '~/types' -import type { iframedToolbarBrowserLogicType } from './iframedToolbarBrowserLogicType' +import type { TeamPublicType, TeamType } from '../../../types' +import type { KeyedAppUrl } from '../AuthorizedUrlList/authorizedUrlListLogic' +import type { HeatmapFilters } from '../heatmaps/types' export type IframedToolbarBrowserLogicProps = { iframeRef: RefObject @@ -45,6 +59,125 @@ export const UserIntentVerb: { 'preview-product-tour': 'preview the product tour', } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface iframedToolbarBrowserLogicValues { + checkUrlIsAuthorized: (url: string) => boolean // authorizedUrlListLogic + urlsKeyed: KeyedAppUrl[] // authorizedUrlListLogic + currentTeam: TeamPublicType | TeamType | null // teamLogic + browserUrl: string | null + commonFilters: CommonFilters + currentFullUrl: string | null + currentPath: string + heatmapColorPalette: string | null + heatmapFilters: HeatmapFilters + heatmapFixedPositionMode: HeatmapFixedPositionMode + iframeBanner: IFrameBanner | null + iframeWidth: number | null + initialPath: string + isBrowserUrlAuthorized: boolean + isProposedBrowserUrlAuthorized: boolean + loading: boolean + proposedBrowserUrl: string | null + viewportRange: { + max: number + min: number + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface iframedToolbarBrowserLogicActions { + addUrl: ( + url: string, + launch?: boolean | undefined + ) => { + launch: boolean | undefined + url: string + } // authorizedUrlListLogic + updateCurrentTeamSuccess: ( + currentTeam: TeamPublicType | TeamType, + payload?: Partial | undefined + ) => { + currentTeam: TeamPublicType | TeamType + payload?: Partial + } // teamLogic + disableElementSelector: () => { + value: true + } + enableElementSelector: () => { + value: true + } + onIframeLoad: () => { + value: true + } + sendToolbarMessage: ( + type: PostHogAppToolbarEvent, + payload?: Record + ) => { + payload: Record | undefined + type: PostHogAppToolbarEvent + } + setBrowserUrl: (url: string | null) => { + url: string | null + } + setCurrentPath: (path: string) => { + path: string + } + setIframeBanner: (banner: IFrameBanner | null) => { + banner: IFrameBanner | null + } + setIframeWidth: (width: number | null) => { + width: number | null + } + setInitialPath: (path: string) => { + path: string + } + setNewActionName: (name: string | null) => { + name: string | null + } + setProposedBrowserUrl: (url: string | null) => { + url: string | null + } + startTrackingLoading: () => { + value: true + } + stopTrackingLoading: () => { + value: true + } + toolbarMessageReceived: ( + type: PostHogAppToolbarEvent, + payload: Record + ) => { + payload: Record + type: PostHogAppToolbarEvent + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface iframedToolbarBrowserLogicMeta { + __keaTypeGenInternalSelectorTypes: { + isBrowserUrlAuthorized: (browserUrl: string | null, checkUrlIsAuthorized: (url: string) => boolean) => boolean + isProposedBrowserUrlAuthorized: ( + proposedBrowserUrl: string | null, + checkUrlIsAuthorized: (url: string) => boolean + ) => boolean + viewportRange: ( + heatmapFilters: HeatmapFilters, + iframeWidth: number | null + ) => { + max: number + min: number + } + currentFullUrl: (browserUrl: string | null, currentPath: string) => string | null + } +} + +export type iframedToolbarBrowserLogicType = MakeLogicType< + iframedToolbarBrowserLogicValues, + iframedToolbarBrowserLogicActions, + IframedToolbarBrowserLogicProps, + iframedToolbarBrowserLogicMeta +> + export const iframedToolbarBrowserLogic = kea([ path(['lib', 'components', 'iframedToolbarBrowser', 'iframedToolbarBrowserLogic']), props({ @@ -168,7 +301,7 @@ export const iframedToolbarBrowserLogic = kea([ selectors({ isBrowserUrlAuthorized: [ (s) => [s.browserUrl, s.checkUrlIsAuthorized], - (browserUrl, checkUrlIsAuthorized) => { + (browserUrl: string | null, checkUrlIsAuthorized: (url: string) => boolean) => { if (!browserUrl) { return false } @@ -177,7 +310,7 @@ export const iframedToolbarBrowserLogic = kea([ ], isProposedBrowserUrlAuthorized: [ (s) => [s.proposedBrowserUrl, s.checkUrlIsAuthorized], - (proposedBrowserUrl, checkUrlIsAuthorized) => { + (proposedBrowserUrl: string | null, checkUrlIsAuthorized: (url: string) => boolean) => { if (!proposedBrowserUrl) { return false } @@ -187,13 +320,13 @@ export const iframedToolbarBrowserLogic = kea([ viewportRange: [ (s) => [s.heatmapFilters, s.iframeWidth], - (heatmapFilters, iframeWidth) => { + (heatmapFilters: import('lib/components/heatmaps/types').HeatmapFilters, iframeWidth: number | null) => { return iframeWidth ? calculateViewportRange(heatmapFilters, iframeWidth) : { min: 0, max: 1800 } }, ], currentFullUrl: [ (s) => [s.browserUrl, s.currentPath], - (browserUrl, currentPath) => { + (browserUrl: string | null, currentPath: string) => { if (!browserUrl) { return null } diff --git a/frontend/src/lib/components/IngestionControls/ingestionControlsLogic.tsx b/frontend/src/lib/components/IngestionControls/ingestionControlsLogic.tsx index 8ff1d82848b1..c7c04394b20d 100644 --- a/frontend/src/lib/components/IngestionControls/ingestionControlsLogic.tsx +++ b/frontend/src/lib/components/IngestionControls/ingestionControlsLogic.tsx @@ -1,9 +1,7 @@ -import { actions, kea, key, listeners, path, props, selectors } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, selectors } from 'kea' import { AccessControlResourceType } from '~/types' -import type { ingestionControlsLogicType } from './ingestionControlsLogicType' - export type IngestionControlsLogicProps = { logicKey: string resourceType: AccessControlResourceType @@ -11,6 +9,37 @@ export type IngestionControlsLogicProps = { onChangeMatchType: (matchType: 'any' | 'all') => void } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface ingestionControlsLogicValues { + logicKey: string + matchType: 'all' | 'any' + resourceType: AccessControlResourceType +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface ingestionControlsLogicActions { + onChangeMatchType: (matchType: 'all' | 'any') => { + matchType: 'all' | 'any' + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface ingestionControlsLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + logicKey: (logicKey: string) => string + resourceType: (resourceType: AccessControlResourceType) => AccessControlResourceType + matchType: (matchType: 'all' | 'any') => 'all' | 'any' + } +} + +export type ingestionControlsLogicType = MakeLogicType< + ingestionControlsLogicValues, + ingestionControlsLogicActions, + IngestionControlsLogicProps, + ingestionControlsLogicMeta +> + export const ingestionControlsLogic = kea([ props({} as IngestionControlsLogicProps), key((props) => props.logicKey), @@ -19,9 +48,9 @@ export const ingestionControlsLogic = kea([ onChangeMatchType: (matchType: 'any' | 'all') => ({ matchType }), }), selectors({ - logicKey: [(_, p) => [p.logicKey], (logicKey) => logicKey], - resourceType: [(_, p) => [p.resourceType], (resourceType) => resourceType], - matchType: [(_, p) => [p.matchType], (matchType) => matchType], + logicKey: [(_, p) => [p.logicKey], (logicKey: string) => logicKey], + resourceType: [(_, p) => [p.resourceType], (resourceType: AccessControlResourceType) => resourceType], + matchType: [(_, p) => [p.matchType], (matchType: 'all' | 'any') => matchType], }), listeners(({ props }) => ({ onChangeMatchType: ({ matchType }) => { diff --git a/frontend/src/lib/components/IngestionControls/triggers/FlagTrigger/flagTriggerLogic.ts b/frontend/src/lib/components/IngestionControls/triggers/FlagTrigger/flagTriggerLogic.ts index 3ea0448d0040..470370e35fde 100644 --- a/frontend/src/lib/components/IngestionControls/triggers/FlagTrigger/flagTriggerLogic.ts +++ b/frontend/src/lib/components/IngestionControls/triggers/FlagTrigger/flagTriggerLogic.ts @@ -1,12 +1,12 @@ -import { actions, afterMount, kea, key, listeners, path, props, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, kea, key, listeners, path, props, selectors } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' import { isObject } from 'lib/utils/guards' import { variantKeyToIndexFeatureFlagPayloads } from 'scenes/feature-flags/featureFlagLogic' +import type { FeatureFlagType } from '../../../../../types' import { LinkedFeatureFlag } from '../../types' -import type { flagTriggerLogicType } from './flagTriggerLogicType' export type FlagTriggerLogicProps = { logicKey: string @@ -14,6 +14,56 @@ export type FlagTriggerLogicProps = { onChange: (flag: LinkedFeatureFlag | null) => void } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface flagTriggerLogicValues { + featureFlag: any + featureFlagLoading: boolean + flag: LinkedFeatureFlag | null + flagHasVariants: boolean + linkedFeatureFlagId: number | null + linkedFlag: any +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface flagTriggerLogicActions { + loadFeatureFlag: () => any + loadFeatureFlagFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadFeatureFlagSuccess: ( + featureFlag: FeatureFlagType | null, + payload?: any + ) => { + featureFlag: FeatureFlagType | null + payload?: any + } + onChange: (flag: LinkedFeatureFlag | null) => { + flag: LinkedFeatureFlag | null + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface flagTriggerLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + linkedFeatureFlagId: (flag: LinkedFeatureFlag | null) => number | null + flag: (flag: LinkedFeatureFlag | null) => LinkedFeatureFlag | null + linkedFlag: (featureFlag: any, flag: LinkedFeatureFlag | null) => any + flagHasVariants: (linkedFlag: any) => boolean + } +} + +export type flagTriggerLogicType = MakeLogicType< + flagTriggerLogicValues, + flagTriggerLogicActions, + FlagTriggerLogicProps, + flagTriggerLogicMeta +> + export const flagTriggerLogic = kea([ props({} as FlagTriggerLogicProps), key((props) => props.logicKey), @@ -33,15 +83,15 @@ export const flagTriggerLogic = kea([ }, })), selectors({ - linkedFeatureFlagId: [(_, p) => [p.flag], (flag) => flag?.id || null], - flag: [(_, p) => [p.flag], (flag) => flag], + linkedFeatureFlagId: [(_, p) => [p.flag], (flag: LinkedFeatureFlag | null) => flag?.id || null], + flag: [(_, p) => [p.flag], (flag: LinkedFeatureFlag | null) => flag], linkedFlag: [ (s, p) => [s.featureFlag, p.flag], // an existing linked flag is loaded from the API, // a newly chosen flag is selected and can be passed in // the original value is used to ensure that we don't // show stale values as people change the selection - (featureFlag, flag) => (flag?.id ? featureFlag : null), + (featureFlag, flag: LinkedFeatureFlag | null) => (flag?.id ? featureFlag : null), ], flagHasVariants: [(s) => [s.linkedFlag], (linkedFlag) => isObject(linkedFlag?.filters.multivariate)], }), diff --git a/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/replayTriggersV2Logic.ts b/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/replayTriggersV2Logic.ts index a63da6c0e63d..c7cd39c526e7 100644 --- a/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/replayTriggersV2Logic.ts +++ b/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/replayTriggersV2Logic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { uuid } from 'lib/utils/dom' @@ -10,7 +10,7 @@ import { SessionRecordingTriggerGroupsConfig, } from '~/lib/components/IngestionControls/types' -import type { replayTriggersV2LogicType } from './replayTriggersV2LogicType' +import type { TeamPublicType, TeamType } from '../../../../../types' /** * A conditionless group at 100% sample rate matches every session, so it's the explicit "record @@ -26,6 +26,121 @@ export function buildRecordEverythingGroup(): SessionRecordingTriggerGroup { } } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface replayTriggersV2LogicValues { + currentTeam: TeamPublicType | TeamType | null // teamLogic + _savingState: boolean | null + _savingStateLoading: boolean + deleteModalGroupId: string | null + editingGroupId: string | null + hasLegacyTriggers: boolean + hasV2Config: boolean + isAddingGroup: boolean + previewLegacyGroups: SessionRecordingTriggerGroup[] + shouldShowMigrationBanner: boolean + showLegacyModal: boolean + triggerGroups: SessionRecordingTriggerGroup[] + triggerGroupsConfig: SessionRecordingTriggerGroupsConfig | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface replayTriggersV2LogicActions { + updateCurrentTeam: (payload: Partial) => Partial // teamLogic + addMultipleTriggerGroups: (groups: SessionRecordingTriggerGroup[]) => { + groups: SessionRecordingTriggerGroup[] + } + addTriggerGroup: (group: SessionRecordingTriggerGroup) => { + group: SessionRecordingTriggerGroup + } + confirmCreateFromLegacy: () => { + value: true + } + confirmCreateFromLegacyFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + confirmCreateFromLegacySuccess: ( + _savingState: boolean, + payload?: { + value: true + } + ) => { + _savingState: boolean + payload?: { + value: true + } + } + deleteTriggerGroup: (id: string) => { + id: string + } + hideCreateFromLegacyModal: () => { + value: true + } + saveConfig: () => any + saveConfigFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + saveConfigSuccess: ( + _savingState: boolean, + payload?: any + ) => { + _savingState: boolean + payload?: any + } + setDeleteModalGroupId: (id: string | null) => { + id: string | null + } + setEditingGroupId: (id: string | null) => { + id: string | null + } + setIsAddingGroup: (isAdding: boolean) => { + isAdding: boolean + } + setTriggerGroupsConfig: (config: SessionRecordingTriggerGroupsConfig | null) => { + config: SessionRecordingTriggerGroupsConfig | null + } + showCreateFromLegacyModal: () => { + value: true + } + updateTriggerGroup: ( + id: string, + updates: Partial + ) => { + id: string + updates: Partial + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface replayTriggersV2LogicMeta { + __keaTypeGenInternalSelectorTypes: { + triggerGroups: ( + triggerGroupsConfig: SessionRecordingTriggerGroupsConfig | null + ) => SessionRecordingTriggerGroup[] + hasV2Config: (triggerGroupsConfig: SessionRecordingTriggerGroupsConfig | null) => boolean + hasLegacyTriggers: (currentTeam: TeamPublicType | TeamType | null) => boolean + shouldShowMigrationBanner: ( + triggerGroups: SessionRecordingTriggerGroup[], + hasLegacyTriggers: boolean + ) => boolean + previewLegacyGroups: (currentTeam: TeamPublicType | TeamType | null) => SessionRecordingTriggerGroup[] + } +} + +export type replayTriggersV2LogicType = MakeLogicType< + replayTriggersV2LogicValues, + replayTriggersV2LogicActions, + Record, + replayTriggersV2LogicMeta +> + export const replayTriggersV2Logic = kea([ path(['lib', 'components', 'IngestionControls', 'triggers', 'triggerGroups', 'replayTriggersV2Logic']), connect({ @@ -155,19 +270,21 @@ export const replayTriggersV2Logic = kea([ selectors({ triggerGroups: [ (s) => [s.triggerGroupsConfig], - (config): SessionRecordingTriggerGroup[] => { + (config: SessionRecordingTriggerGroupsConfig | null): SessionRecordingTriggerGroup[] => { return config?.groups || [] }, ], hasV2Config: [ (s) => [s.triggerGroupsConfig], - (config): boolean => { + (config: SessionRecordingTriggerGroupsConfig | null): boolean => { return config !== null && config.version === 2 }, ], hasLegacyTriggers: [ (s) => [s.currentTeam], - (team): boolean => { + ( + team: null | import('../../../../../types').TeamPublicType | import('../../../../../types').TeamType + ): boolean => { if (!team) { return false } @@ -182,14 +299,16 @@ export const replayTriggersV2Logic = kea([ ], shouldShowMigrationBanner: [ (s) => [s.triggerGroups, s.hasLegacyTriggers], - (triggerGroups, hasLegacyTriggers): boolean => { + (triggerGroups: SessionRecordingTriggerGroup[], hasLegacyTriggers: boolean): boolean => { // Show banner if there are legacy triggers configured but no V2 groups return hasLegacyTriggers && triggerGroups.length === 0 }, ], previewLegacyGroups: [ (s) => [s.currentTeam], - (team): SessionRecordingTriggerGroup[] => { + ( + team: null | import('../../../../../types').TeamPublicType | import('../../../../../types').TeamType + ): SessionRecordingTriggerGroup[] => { if (!team) { return [] } diff --git a/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/triggerGroupFormLogic.ts b/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/triggerGroupFormLogic.ts index 8f13ff0dd93b..866fb94d63f4 100644 --- a/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/triggerGroupFormLogic.ts +++ b/frontend/src/lib/components/IngestionControls/triggers/triggerGroups/triggerGroupFormLogic.ts @@ -1,5 +1,6 @@ -import { actions, kea, key, listeners, path, props, reducers } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, reducers } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { lemonToast } from '@posthog/lemon-ui' @@ -13,8 +14,6 @@ import { UrlTriggerConfig, } from '~/lib/components/IngestionControls/types' -import type { triggerGroupFormLogicType } from './triggerGroupFormLogicType' - function isValidRegex(pattern: string): boolean { try { new RegExp(pattern) @@ -35,6 +34,221 @@ export interface TriggerGroupFormLogicProps { onCancel: () => void } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface triggerGroupFormLogicValues { + expandedEvent: string | null + isAddingUrl: boolean + isTriggerGroupSubmitting: boolean + isTriggerGroupValid: boolean + newUrl: string + showTriggerGroupErrors: boolean + testUrl: string + triggerGroup: { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + } + triggerGroupAllErrors: Record + triggerGroupChanged: boolean + triggerGroupErrors: DeepPartialMap< + { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + }, + ValidationErrorType + > + triggerGroupHasErrors: boolean + triggerGroupManualErrors: Record + triggerGroupTouched: boolean + triggerGroupTouches: Record + triggerGroupValidationErrors: DeepPartialMap< + { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + }, + ValidationErrorType + > +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface triggerGroupFormLogicActions { + addFlag: ( + _id: number, + key: string + ) => { + key: string + } + addUrl: (url: string) => { + url: string + } + removeEvent: (eventName: string) => { + eventName: string + } + removeFlag: () => { + value: true + } + removeUrl: (url: string) => { + url: string + } + resetTriggerGroup: (values?: { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + }) => { + values?: { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + } + } + setEventProperties: ( + eventName: string, + properties: TriggerPropertyFilter[] + ) => { + eventName: string + properties: TriggerPropertyFilter[] + } + setExpandedEvent: (eventName: string | null) => { + eventName: string | null + } + setIsAddingUrl: (isAdding: boolean) => { + isAdding: boolean + } + setNewUrl: (url: string) => { + url: string + } + setTestUrl: (url: string) => { + url: string + } + setTriggerGroupManualErrors: (errors: Record) => { + errors: Record + } + setTriggerGroupValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setTriggerGroupValues: ( + values: DeepPartial<{ + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + }> + ) => { + values: DeepPartial<{ + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + }> + } + submitTriggerGroup: () => { + value: boolean + } + submitTriggerGroupFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitTriggerGroupRequest: (triggerGroup: { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + }) => { + triggerGroup: { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + } + } + submitTriggerGroupSuccess: (triggerGroup: { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + }) => { + triggerGroup: { + events: EventTriggerConfig[] + flag: string | null + matchType: 'all' | 'any' + minDurationMs: number | null + name: string + properties: TriggerPropertyFilter[] + sampleRate: number + urls: UrlTriggerConfig[] + } + } + touchTriggerGroupField: (key: string) => { + key: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface triggerGroupFormLogicMeta { + key: string +} + +export type triggerGroupFormLogicType = MakeLogicType< + triggerGroupFormLogicValues, + triggerGroupFormLogicActions, + TriggerGroupFormLogicProps, + triggerGroupFormLogicMeta +> + export const triggerGroupFormLogic = kea([ path(['lib', 'components', 'IngestionControls', 'triggers', 'triggerGroups', 'triggerGroupFormLogic']), props({} as TriggerGroupFormLogicProps), diff --git a/frontend/src/lib/components/IngestionControls/triggers/urlConfigLogic.ts b/frontend/src/lib/components/IngestionControls/triggers/urlConfigLogic.ts index 6bf9d93fa1e6..1ada5f7345a3 100644 --- a/frontend/src/lib/components/IngestionControls/triggers/urlConfigLogic.ts +++ b/frontend/src/lib/components/IngestionControls/triggers/urlConfigLogic.ts @@ -1,10 +1,9 @@ -import { actions, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { UrlTriggerConfig } from 'lib/components/IngestionControls/types' -import type { urlConfigLogicType } from './urlConfigLogicType' - const NEW_URL_TRIGGER = { url: '', matching: 'regex' } export function isStringWithLength(x: unknown): x is string { @@ -23,6 +22,139 @@ export interface UrlConfigLogicProps { onChange: (urlTriggerConfig: UrlTriggerConfig[]) => void } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface urlConfigLogicValues { + checkUrlTrigger: string + checkUrlTriggerResults: { + [key: number]: boolean + } + editUrlTriggerIndex: number | null + isAddUrlTriggerConfigFormVisible: boolean + isProposedUrlTriggerSubmitting: boolean + isProposedUrlTriggerValid: boolean + proposedUrlTrigger: UrlTriggerConfig + proposedUrlTriggerAllErrors: Record + proposedUrlTriggerChanged: boolean + proposedUrlTriggerErrors: DeepPartialMap + proposedUrlTriggerHasErrors: boolean + proposedUrlTriggerManualErrors: Record + proposedUrlTriggerTouched: boolean + proposedUrlTriggerTouches: Record + proposedUrlTriggerValidationErrors: DeepPartialMap + showProposedUrlTriggerErrors: boolean + urlTriggerConfig: UrlTriggerConfig[] + urlTriggerInputValidationWarning: string | null + urlTriggerToEdit: { + matching: string + url: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface urlConfigLogicActions { + addUrlTrigger: (urlTriggerConfig: UrlTriggerConfig) => { + urlTriggerConfig: UrlTriggerConfig + } + cancelProposingUrlTrigger: () => { + value: true + } + newUrlTrigger: () => { + value: true + } + removeUrlTrigger: (index: number) => { + index: number + } + resetProposedUrlTrigger: (values?: UrlTriggerConfig) => { + values?: UrlTriggerConfig + } + setCheckUrlBlocklist: (url: string) => { + url: string + } + setCheckUrlTrigger: (url: string) => { + url: string + } + setEditUrlTriggerIndex: (originalIndex: number | null) => { + originalIndex: number | null + } + setProposedUrlTriggerManualErrors: (errors: Record) => { + errors: Record + } + setProposedUrlTriggerValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setProposedUrlTriggerValues: (values: DeepPartial) => { + values: DeepPartial + } + setUrlTriggerConfig: (urlTriggerConfig: UrlTriggerConfig[]) => { + urlTriggerConfig: UrlTriggerConfig[] + } + submitProposedUrlTrigger: () => { + value: boolean + } + submitProposedUrlTriggerFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitProposedUrlTriggerRequest: (proposedUrlTrigger: UrlTriggerConfig) => { + proposedUrlTrigger: UrlTriggerConfig + } + submitProposedUrlTriggerSuccess: (proposedUrlTrigger: UrlTriggerConfig) => { + proposedUrlTrigger: UrlTriggerConfig + } + touchProposedUrlTriggerField: (key: string) => { + key: string + } + updateUrlTrigger: ( + index: number, + urlTriggerConfig: UrlTriggerConfig + ) => { + index: number + urlTriggerConfig: UrlTriggerConfig + } + validateUrlInput: ( + url: string, + type: 'blocklist' | 'trigger' + ) => { + type: 'blocklist' | 'trigger' + url: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface urlConfigLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + isAddUrlTriggerConfigFormVisible: (editUrlTriggerIndex: number | null) => boolean + urlTriggerToEdit: ( + urlTriggerConfig: UrlTriggerConfig[], + editUrlTriggerIndex: number | null + ) => { + matching: string + url: string + } + checkUrlTriggerResults: ( + checkUrlTrigger: string, + urlTriggerConfig: UrlTriggerConfig[] + ) => { + [key: number]: boolean + } + } +} + +export type urlConfigLogicType = MakeLogicType< + urlConfigLogicValues, + urlConfigLogicActions, + UrlConfigLogicProps, + urlConfigLogicMeta +> + export const urlConfigLogic = kea([ props({} as UrlConfigLogicProps), key((props) => props.logicKey), @@ -99,11 +231,11 @@ export const urlConfigLogic = kea([ selectors({ isAddUrlTriggerConfigFormVisible: [ (s) => [s.editUrlTriggerIndex], - (editUrlTriggerIndex) => editUrlTriggerIndex === -1, + (editUrlTriggerIndex: number | null) => editUrlTriggerIndex === -1, ], urlTriggerToEdit: [ (s) => [s.urlTriggerConfig, s.editUrlTriggerIndex], - (urlTriggerConfig, editUrlTriggerIndex) => { + (urlTriggerConfig: UrlTriggerConfig[], editUrlTriggerIndex: number | null) => { if ( editUrlTriggerIndex === null || editUrlTriggerIndex === -1 || @@ -117,7 +249,7 @@ export const urlConfigLogic = kea([ checkUrlTriggerResults: [ (s) => [s.checkUrlTrigger, s.urlTriggerConfig], - (checkUrl, urlTriggerConfig): { [key: number]: boolean } => { + (checkUrl: string, urlTriggerConfig: UrlTriggerConfig[]): { [key: number]: boolean } => { if (!checkUrl.trim() || !urlTriggerConfig) { return {} } diff --git a/frontend/src/lib/components/LiveUserCount/liveUserCountLogic.ts b/frontend/src/lib/components/LiveUserCount/liveUserCountLogic.ts index 20fbc1d3ff4a..d7cee8da0bca 100644 --- a/frontend/src/lib/components/LiveUserCount/liveUserCountLogic.ts +++ b/frontend/src/lib/components/LiveUserCount/liveUserCountLogic.ts @@ -1,9 +1,9 @@ -import { actions, connect, events, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, events, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { liveEventsHostOrigin } from 'lib/utils/apiHost' import { teamLogic } from 'scenes/teamLogic' -import type { liveUserCountLogicType } from './liveUserCountLogicType' +import type { TeamPublicType, TeamType } from '../../../types' export interface LiveUserCountStats { users_on_product?: number @@ -14,6 +14,61 @@ export interface LiveUserCountLogicProps { pollIntervalMs?: number } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface liveUserCountLogicValues { + currentTeam: TeamPublicType | TeamType | null // teamLogic + activeRecordings: number | null + isHovering: boolean + liveUserCount: number | null + now: Date | null + stats: LiveUserCountStats | null + statsUpdatedSecondsAgo: number | null + statsUpdatedTime: Date | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface liveUserCountLogicActions { + pauseStream: () => { + value: true + } + pollStats: () => { + value: true + } + resumeStream: () => { + value: true + } + setIsHovering: (isHovering: boolean) => { + isHovering: boolean + } + setNow: (now: Date) => { + now: Date + } + setStats: ( + stats: LiveUserCountStats, + now: Date + ) => { + now: Date + stats: LiveUserCountStats + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface liveUserCountLogicMeta { + key: number + __keaTypeGenInternalSelectorTypes: { + liveUserCount: (stats: LiveUserCountStats | null) => number | null + activeRecordings: (stats: LiveUserCountStats | null) => number | null + statsUpdatedSecondsAgo: (statsUpdatedTime: Date | null, now: Date | null) => number | null + } +} + +export type liveUserCountLogicType = MakeLogicType< + liveUserCountLogicValues, + liveUserCountLogicActions, + LiveUserCountLogicProps, + liveUserCountLogicMeta +> + export const liveUserCountLogic = kea([ path((key) => ['lib', 'components', 'LiveUserCount', 'liveUserCountLogic', key]), key((props) => props.pollIntervalMs ?? 30000), @@ -57,8 +112,8 @@ export const liveUserCountLogic = kea([ ], }), selectors({ - liveUserCount: [(s) => [s.stats], (stats) => stats?.users_on_product ?? null], - activeRecordings: [(s) => [s.stats], (stats) => stats?.active_recordings ?? null], + liveUserCount: [(s) => [s.stats], (stats: LiveUserCountStats | null) => stats?.users_on_product ?? null], + activeRecordings: [(s) => [s.stats], (stats: LiveUserCountStats | null) => stats?.active_recordings ?? null], statsUpdatedSecondsAgo: [ (s) => [s.statsUpdatedTime, s.now], (statsUpdatedTime: Date | null, now: Date | null) => { diff --git a/frontend/src/lib/components/MCPHint/mcpHintLogic.tsx b/frontend/src/lib/components/MCPHint/mcpHintLogic.tsx index b44759930f6b..4e4feb0348ec 100644 --- a/frontend/src/lib/components/MCPHint/mcpHintLogic.tsx +++ b/frontend/src/lib/components/MCPHint/mcpHintLogic.tsx @@ -1,4 +1,4 @@ -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { toast } from 'react-toastify' @@ -12,7 +12,7 @@ import { userLogic } from 'scenes/userLogic' import { UserType } from '~/types' -import type { mcpHintLogicType } from './mcpHintLogicType' +import type { FeatureFlagsSet } from '../../logic/featureFlagLogic' import { MCPHintToast } from './MCPHintToast' import type { SurfaceKey } from './prompts' @@ -41,6 +41,123 @@ export function tryShowMCPHint(surfaceKey: SurfaceKey, options: TryShowMCPHintOp } } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface mcpHintLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + user: UserType | null // userLogic + dismissedSurfaces: Record + effectiveOptOut: boolean + lastShownAt: number | null + localGlobalOptOut: boolean + topEvents: string[] + topEventsLoading: boolean + userRole: string | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface mcpHintLogicActions { + reportMCPHintDismissed: ( + dismissType: 'all' | 'surface', + surfaceKey?: string | undefined + ) => { + dismissType: 'all' | 'surface' + surfaceKey: string | undefined + } // eventUsageLogic + reportMCPHintShown: (surfaceKey: string) => { + surfaceKey: string + } // eventUsageLogic + updateUser: ( + user: Partial, + successCallback?: (() => void) | undefined + ) => { + successCallback: (() => void) | undefined + user: Partial + } // userLogic + dismissAll: () => { + value: true + } + dismissSurface: (surfaceKey: SurfaceKey) => { + surfaceKey: + | 'actions.create' + | 'alerts.create' + | 'annotations.create' + | 'cohorts.create' + | 'dashboards.create' + | 'data_warehouse_sources.create' + | 'data_warehouse_sources.update' + | 'early_access_features.create' + | 'error_tracking.assign' + | 'experiments.create' + | 'experiments.launch' + | 'feature_flags.create' + | 'feature_flags.update' + | 'insights.create' + | 'sql.execute' + | 'surveys.create' + | 'workflows.create' + } + loadTopEvents: () => any + loadTopEventsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadTopEventsSuccess: ( + topEvents: string[], + payload?: any + ) => { + topEvents: string[] + payload?: any + } + recordShown: (now: number) => { + now: number + } + reenable: () => { + value: true + } + tryShowHint: ( + surfaceKey: SurfaceKey, + derivedPrompt?: string + ) => { + derivedPrompt: string | undefined + surfaceKey: + | 'actions.create' + | 'alerts.create' + | 'annotations.create' + | 'cohorts.create' + | 'dashboards.create' + | 'data_warehouse_sources.create' + | 'data_warehouse_sources.update' + | 'early_access_features.create' + | 'error_tracking.assign' + | 'experiments.create' + | 'experiments.launch' + | 'feature_flags.create' + | 'feature_flags.update' + | 'insights.create' + | 'sql.execute' + | 'surveys.create' + | 'workflows.create' + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface mcpHintLogicMeta { + __keaTypeGenInternalSelectorTypes: { + effectiveOptOut: (localGlobalOptOut: boolean, user: UserType | null) => boolean + userRole: (user: UserType | null) => string | null + } +} + +export type mcpHintLogicType = MakeLogicType< + mcpHintLogicValues, + mcpHintLogicActions, + Record, + mcpHintLogicMeta +> + export const mcpHintLogic = kea([ path(['lib', 'components', 'MCPHint', 'mcpHintLogic']), connect(() => ({ diff --git a/frontend/src/lib/components/Metalytics/metalyticsLogic.ts b/frontend/src/lib/components/Metalytics/metalyticsLogic.ts index bcd8099082d2..694329fce313 100644 --- a/frontend/src/lib/components/Metalytics/metalyticsLogic.ts +++ b/frontend/src/lib/components/Metalytics/metalyticsLogic.ts @@ -1,4 +1,4 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { loaders } from 'kea-loaders' import { subscriptions } from 'kea-subscriptions' @@ -11,7 +11,80 @@ import { sidePanelContextLogic } from '~/layout/navigation-3000/sidepanel/sidePa import { SidePanelSceneContext } from '~/layout/navigation-3000/sidepanel/types' import { hogql } from '~/queries/utils' -import type { metalyticsLogicType } from './metalyticsLogicType' +import type { OrganizationMemberType } from '../../../types' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface metalyticsLogicValues { + members: OrganizationMemberType[] | null // membersLogic + sceneSidePanelContext: SidePanelSceneContext // sidePanelContextLogic + currentProjectId: number | string // teamLogic + instanceId: string | null + recentUserMembers: OrganizationMemberType[] + recentUsers: string[] + recentUsersLoading: boolean + scope: string | undefined + viewCount: { + users: number + views: number + } | null + viewCountLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface metalyticsLogicActions { + loadUsersLast30days: () => any + loadUsersLast30daysFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadUsersLast30daysSuccess: ( + recentUsers: string[], + payload?: any + ) => { + recentUsers: string[] + payload?: any + } + loadViewCount: () => any + loadViewCountFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadViewCountSuccess: ( + viewCount: { + users: number + views: number + }, + payload?: any + ) => { + viewCount: { + users: number + views: number + } + payload?: any + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface metalyticsLogicMeta { + __keaTypeGenInternalSelectorTypes: { + instanceId: (sceneSidePanelContext: SidePanelSceneContext) => string | null + scope: (sceneSidePanelContext: SidePanelSceneContext) => string | undefined + recentUserMembers: (recentUsers: string[], members: OrganizationMemberType[] | null) => OrganizationMemberType[] + } +} + +export type metalyticsLogicType = MakeLogicType< + metalyticsLogicValues, + metalyticsLogicActions, + Record, + metalyticsLogicMeta +> export const metalyticsLogic = kea([ path(['lib', 'components', 'metalytics', 'metalyticsLogic']), @@ -90,7 +163,7 @@ export const metalyticsLogic = kea([ recentUserMembers: [ (s) => [s.recentUsers, s.members], - (recentUsers, members) => { + (recentUsers: string[], members: import('../../../types').OrganizationMemberType[] | null) => { if (!members || !recentUsers) { return [] } diff --git a/frontend/src/lib/components/NavPanelAdvertisement/NavPanelAdvertisementLogic.ts b/frontend/src/lib/components/NavPanelAdvertisement/NavPanelAdvertisementLogic.ts index f397bffe7d26..9fa1024791c8 100644 --- a/frontend/src/lib/components/NavPanelAdvertisement/NavPanelAdvertisementLogic.ts +++ b/frontend/src/lib/components/NavPanelAdvertisement/NavPanelAdvertisementLogic.ts @@ -1,11 +1,32 @@ -import { actions, kea, key, path, props, reducers } from 'kea' - -import type { navPanelAdvertisementLogicType } from './NavPanelAdvertisementLogicType' +import { MakeLogicType, actions, kea, key, path, props, reducers } from 'kea' export type NavPanelAdvertisementLogicProps = { campaign: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelAdvertisementLogicValues { + hidden: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelAdvertisementLogicActions { + hideAdvertisement: () => boolean + showAdvertisement: () => boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelAdvertisementLogicMeta { + key: string +} + +export type navPanelAdvertisementLogicType = MakeLogicType< + navPanelAdvertisementLogicValues, + navPanelAdvertisementLogicActions, + NavPanelAdvertisementLogicProps, + navPanelAdvertisementLogicMeta +> + export const navPanelAdvertisementLogic = kea([ path(['lib', 'components', 'NavPanelAdvertisementLogic']), props({} as NavPanelAdvertisementLogicProps), diff --git a/frontend/src/lib/components/NavPanelAdvertisement/navPanelAdvertisementRecommendedLogic.ts b/frontend/src/lib/components/NavPanelAdvertisement/navPanelAdvertisementRecommendedLogic.ts index 497fbb589e97..bd726fdc99af 100644 --- a/frontend/src/lib/components/NavPanelAdvertisement/navPanelAdvertisementRecommendedLogic.ts +++ b/frontend/src/lib/components/NavPanelAdvertisement/navPanelAdvertisementRecommendedLogic.ts @@ -1,16 +1,36 @@ -import { connect, kea, path, selectors } from 'kea' +import { MakeLogicType, connect, kea, path, selectors } from 'kea' import { customProductsLogic } from '~/layout/panel-layout/ProjectTree/customProductsLogic' import { type UserProductListItem, UserProductListReason } from '~/queries/schema/schema-general' -import type { navPanelAdvertisementRecommendedLogicType } from './navPanelAdvertisementRecommendedLogicType' - const RECOMMENDED_PRODUCT_CREATED_AT_THRESHOLD_IN_DAYS = 7 const RECOMMENDED_PRODUCT_REASONS: UserProductListReason[] = [ UserProductListReason.SALES_LED, UserProductListReason.NEW_PRODUCT, ] +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelAdvertisementRecommendedLogicValues { + customProducts: UserProductListItem[] // customProductsLogic + oldestRecommendedProduct: UserProductListItem | null + recommendedProducts: UserProductListItem[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelAdvertisementRecommendedLogicMeta { + __keaTypeGenInternalSelectorTypes: { + recommendedProducts: (customProducts: UserProductListItem[]) => UserProductListItem[] + oldestRecommendedProduct: (recommendedProducts: UserProductListItem[]) => UserProductListItem | null + } +} + +export type navPanelAdvertisementRecommendedLogicType = MakeLogicType< + navPanelAdvertisementRecommendedLogicValues, + {}, + Record, + navPanelAdvertisementRecommendedLogicMeta +> + export const navPanelAdvertisementRecommendedLogic = kea([ path(['lib', 'components', 'NavPanelAdvertisement', 'navPanelAdvertisementRecommendedLogic']), connect(() => ({ diff --git a/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushAdLogic.ts b/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushAdLogic.ts index e5447cc61f88..7bba0f2b2923 100644 --- a/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushAdLogic.ts +++ b/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushAdLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, selectors } from 'kea' import posthog from 'posthog-js' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' @@ -9,9 +9,9 @@ import { FileSystemImport, ProductIntentContext, ProductKey } from '~/queries/sc import type { ProductPushCampaignApi } from 'products/growth/frontend/generated/api.schemas' +import type { FeatureFlagsSet } from '../../logic/featureFlagLogic' import type { ProductPushDisplay } from './navPanelAdShared' import { navPanelAdvertisementLogic } from './NavPanelAdvertisementLogic' -import type { navPanelProductPushAdLogicType } from './navPanelProductPushAdLogicType' import { getProductPushDisplay } from './navPanelProductPushDisplay' export type NavPanelProductPushAdLogicProps = { @@ -22,6 +22,47 @@ export type NavPanelProductPushAdLogicProps = { // card's dismiss button), so key it the same way here to read the same `hidden` flag. const dismissKey = (campaign: ProductPushCampaignApi): string => `product-push-${campaign.id}` +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelProductPushAdLogicValues { + featureFlags: FeatureFlagsSet // featureFlagLogic + hidden: boolean // navPanelAdvertisementLogic + display: ProductPushDisplay + flagGated: boolean + productInfo: FileSystemImport | undefined + shouldRender: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelProductPushAdLogicActions { + reportAdClicked: () => { + value: true + } + reportAdDismissed: () => { + value: true + } + reportAdShown: () => { + value: true + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelProductPushAdLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + productInfo: (arg: any) => FileSystemImport | undefined + display: (arg: any) => ProductPushDisplay + flagGated: (productInfo: FileSystemImport | undefined, featureFlags: FeatureFlagsSet) => boolean + shouldRender: (hidden: boolean, productInfo: FileSystemImport | undefined, flagGated: boolean) => boolean + } +} + +export type navPanelProductPushAdLogicType = MakeLogicType< + navPanelProductPushAdLogicValues, + navPanelProductPushAdLogicActions, + NavPanelProductPushAdLogicProps, + navPanelProductPushAdLogicMeta +> + export const navPanelProductPushAdLogic = kea([ path(['lib', 'components', 'NavPanelAdvertisement', 'navPanelProductPushAdLogic']), props({} as NavPanelProductPushAdLogicProps), @@ -52,12 +93,15 @@ export const navPanelProductPushAdLogic = kea([ // Never advertise a product this user can't open (mirrors the sidebar's flag filtering) flagGated: [ (s) => [s.productInfo, s.featureFlags], - (productInfo, featureFlags): boolean => - !!productInfo?.flag && !(featureFlags as Record)[productInfo.flag], + ( + productInfo: FileSystemImport | undefined, + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet + ): boolean => !!productInfo?.flag && !(featureFlags as Record)[productInfo.flag], ], shouldRender: [ (s) => [s.hidden, s.productInfo, s.flagGated], - (hidden, productInfo, flagGated): boolean => !hidden && !!productInfo && !flagGated, + (hidden: boolean, productInfo: FileSystemImport | undefined, flagGated: boolean): boolean => + !hidden && !!productInfo && !flagGated, ], }), listeners(({ props }) => ({ diff --git a/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushLogic.ts b/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushLogic.ts index 1b55c22ee24d..dc9d00188b41 100644 --- a/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushLogic.ts +++ b/frontend/src/lib/components/NavPanelAdvertisement/navPanelProductPushLogic.ts @@ -1,4 +1,4 @@ -import { afterMount, connect, kea, listeners, path } from 'kea' +import { MakeLogicType, afterMount, connect, kea, listeners, path } from 'kea' import { loaders } from 'kea-loaders' import { preflightLogic } from 'lib/logic/preflightLogic' @@ -8,7 +8,40 @@ import { teamLogic } from 'scenes/teamLogic' import * as api from 'products/growth/frontend/generated/api' import type { ProductPushCampaignApi } from 'products/growth/frontend/generated/api.schemas' -import type { navPanelProductPushLogicType } from './navPanelProductPushLogicType' +import type { OrganizationType } from '../../../types' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelProductPushLogicValues { + currentOrganization: OrganizationType | null // organizationLogic + isCloudOrDev: boolean | undefined // preflightLogic + currentTeamId: number | null // teamLogic + activeCampaign: ProductPushCampaignApi | null + activeCampaignLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface navPanelProductPushLogicActions { + loadActiveCampaign: () => any + loadActiveCampaignFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadActiveCampaignSuccess: ( + activeCampaign: ProductPushCampaignApi | null, + payload?: any + ) => { + activeCampaign: ProductPushCampaignApi | null + payload?: any + } +} + +export type navPanelProductPushLogicType = MakeLogicType< + navPanelProductPushLogicValues, + navPanelProductPushLogicActions +> export const navPanelProductPushLogic = kea([ path(['lib', 'components', 'NavPanelAdvertisement', 'navPanelProductPushLogic']), diff --git a/frontend/src/lib/components/NotificationsMenu/notificationsMenuLogic.tsx b/frontend/src/lib/components/NotificationsMenu/notificationsMenuLogic.tsx index 951033c01fd5..a17a9be64175 100644 --- a/frontend/src/lib/components/NotificationsMenu/notificationsMenuLogic.tsx +++ b/frontend/src/lib/components/NotificationsMenu/notificationsMenuLogic.tsx @@ -1,12 +1,45 @@ -import { actions, connect, kea, listeners, path, reducers } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers } from 'kea' import { sidePanelNotificationsLogic } from '~/layout/navigation-3000/sidepanel/panels/activity/sidePanelNotificationsLogic' import { panelLayoutLogic } from '~/layout/panel-layout/panelLayoutLogic' -import type { notificationsMenuLogicType } from './notificationsMenuLogicType' +import type { PanelLayoutNavIdentifier } from '../../../layout/panel-layout/panelLayoutLogic' export type NotificationTab = 'all' | 'unread' | 'archived' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface notificationsMenuLogicValues { + activeTab: NotificationTab + isNotificationsMenuOpen: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface notificationsMenuLogicActions { + setActivePanelIdentifier: (identifier: PanelLayoutNavIdentifier) => { + identifier: PanelLayoutNavIdentifier + } // panelLayoutLogic + showLayoutPanel: (visible: boolean) => { + visible: boolean + } // panelLayoutLogic + loadArchivedNotifications: () => { + value: true + } // sidePanelNotificationsLogic + openToUnread: () => { + value: true + } + setActiveTab: (tab: NotificationTab) => { + tab: NotificationTab + } + setNotificationsMenuOpen: (isOpen: boolean) => { + isOpen: boolean + } + toggleNotificationsMenu: () => { + value: true + } +} + +export type notificationsMenuLogicType = MakeLogicType + export const notificationsMenuLogic = kea([ path(['lib', 'components', 'NotificationsMenu', 'notificationsMenuLogic']), connect(() => ({ diff --git a/frontend/src/lib/components/ObjectTags/objectTagsLogic.ts b/frontend/src/lib/components/ObjectTags/objectTagsLogic.ts index 9e1d32d792c6..e8572775f942 100644 --- a/frontend/src/lib/components/ObjectTags/objectTagsLogic.ts +++ b/frontend/src/lib/components/ObjectTags/objectTagsLogic.ts @@ -1,9 +1,7 @@ -import { actions, kea, key, listeners, path, props, reducers } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, reducers } from 'kea' import { uniqueBy } from 'lib/utils/arrays' -import type { objectTagsLogicType } from './objectTagsLogicType' - export interface ObjectTagsLogicProps { id: string | number onChange?: (tags: string[]) => void @@ -14,6 +12,33 @@ function cleanTag(tag?: string): string { return (tag ?? '').trim().toLowerCase() } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface objectTagsLogicValues { + editingTags: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface objectTagsLogicActions { + setEditingTags: (editingTags: boolean) => { + editingTags: boolean + } + setTags: (tags: string[]) => { + tags: string[] + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface objectTagsLogicMeta { + key: number | string +} + +export type objectTagsLogicType = MakeLogicType< + objectTagsLogicValues, + objectTagsLogicActions, + ObjectTagsLogicProps, + objectTagsLogicMeta +> + export const objectTagsLogic = kea([ path(['lib', 'components', 'ObjectTags', 'objectTagsLogic']), props({} as ObjectTagsLogicProps), diff --git a/frontend/src/lib/components/PayGateMini/PayGateButton.tsx b/frontend/src/lib/components/PayGateMini/PayGateButton.tsx index acbbe5305ca4..5db3b49b683a 100644 --- a/frontend/src/lib/components/PayGateMini/PayGateButton.tsx +++ b/frontend/src/lib/components/PayGateMini/PayGateButton.tsx @@ -9,7 +9,7 @@ import { paymentEntryLogic } from 'scenes/billing/paymentEntryLogic' import { BillingProductV2Type } from '~/types' import { PayGateMiniLogicProps, payGateMiniLogic } from './payGateMiniLogic' -import { payGateMiniLogicType } from './payGateMiniLogicType' +import type { payGateMiniLogicType } from './payGateMiniLogic' type UsePayGateButtonReturn = Pick< payGateMiniLogicType['values'], diff --git a/frontend/src/lib/components/PayGateMini/payGateMiniLogic.tsx b/frontend/src/lib/components/PayGateMini/payGateMiniLogic.tsx index 648d28ca731d..a60a37325da7 100644 --- a/frontend/src/lib/components/PayGateMini/payGateMiniLogic.tsx +++ b/frontend/src/lib/components/PayGateMini/payGateMiniLogic.tsx @@ -1,4 +1,4 @@ -import { actions, connect, kea, key, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, key, path, props, reducers, selectors } from 'kea' import { preflightLogic } from 'lib/logic/preflightLogic' import { billingLogic } from 'scenes/billing/billingLogic' @@ -6,7 +6,7 @@ import { userLogic } from 'scenes/userLogic' import { AvailableFeature, BillingProductV2AddonType, BillingProductV2Type } from '~/types' -import type { payGateMiniLogicType } from './payGateMiniLogicType' +import type { BillingFeatureType, BillingPlanType, BillingType, UserType } from '../../../types' export interface PayGateMiniLogicProps { feature: AvailableFeature @@ -15,6 +15,100 @@ export interface PayGateMiniLogicProps { export type GateVariantType = 'add-card' | 'contact-sales' | 'move-to-cloud' | null +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface payGateMiniLogicValues { + billing: BillingType | null // billingLogic + billingLoading: boolean // billingLogic + isCloudOrDev: boolean | undefined // preflightLogic + availableFeature: (feature: AvailableFeature) => BillingFeatureType | null | undefined // userLogic + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean // userLogic + user: UserType | null // userLogic + addonTrialModalOpen: boolean + bypassPaywall: boolean + ctaLabel: 'Contact sales' | 'Move to PostHog Cloud' | 'Upgrade now' | 'View plans' + ctaLink: string | undefined + featureAvailableOnOrg: BillingFeatureType | null | undefined + featureInfo: BillingFeatureType | undefined + featureInfoOnNextPlan: BillingFeatureType | undefined + gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null + isAddonProduct: boolean | undefined + isPaymentEntryFlow: boolean + minimumPlanWithFeature: BillingPlanType | undefined + nextPlanWithFeature: BillingPlanType | null | undefined + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface payGateMiniLogicActions { + closeAddonTrialModal: () => { + value: true + } + openAddonTrialModal: () => { + value: true + } + setBypassPaywall: (bypassPaywall: boolean) => { + bypassPaywall: boolean + } + setGateVariant: (gateVariant: GateVariantType) => { + gateVariant: GateVariantType + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface payGateMiniLogicMeta { + key: AvailableFeature + __keaTypeGenInternalSelectorTypes: { + productWithFeature: ( + billing: BillingType | null + ) => BillingProductV2AddonType | BillingProductV2Type | undefined + isAddonProduct: ( + billing: BillingType | null, + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined + ) => boolean | undefined + featureInfo: ( + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined + ) => BillingFeatureType | undefined + featureAvailableOnOrg: (user: UserType | null, arg: any) => BillingFeatureType | null | undefined + minimumPlanWithFeature: ( + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined + ) => BillingPlanType | undefined + nextPlanWithFeature: ( + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined + ) => BillingPlanType | null | undefined + featureInfoOnNextPlan: ( + nextPlanWithFeature: BillingPlanType | null | undefined + ) => BillingFeatureType | undefined + gateVariant: ( + billingLoading: boolean, + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean, // userLogic + minimumPlanWithFeature: BillingPlanType | undefined, + arg: any, + arg2: any + ) => 'add-card' | 'contact-sales' | 'move-to-cloud' | null + ctaLink: ( + gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null, + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined, + featureInfo: BillingFeatureType | undefined + ) => string | undefined + ctaLabel: ( + gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null, + isPaymentEntryFlow: boolean + ) => 'Contact sales' | 'Move to PostHog Cloud' | 'Upgrade now' | 'View plans' + isPaymentEntryFlow: ( + gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null, + isAddonProduct: boolean | undefined, + billing: BillingType | null + ) => boolean + } +} + +export type payGateMiniLogicType = MakeLogicType< + payGateMiniLogicValues, + payGateMiniLogicActions, + PayGateMiniLogicProps, + payGateMiniLogicMeta +> + export const payGateMiniLogic = kea([ props({} as PayGateMiniLogicProps), path(['lib', 'components', 'payGateMini', 'payGateMiniLogic']), @@ -54,7 +148,7 @@ export const payGateMiniLogic = kea([ selectors(({ values, props }) => ({ productWithFeature: [ (s) => [s.billing], - (billing) => { + (billing: null | import('~/types').BillingType) => { // TODO(@zach): revisit this logic after subscribe to all products is released // There are some features where we want to check the product first const checkProductFirst = [AvailableFeature.ORGANIZATIONS_PROJECTS] @@ -85,29 +179,33 @@ export const payGateMiniLogic = kea([ ], isAddonProduct: [ (s) => [s.billing, s.productWithFeature], - (billing, productWithFeature) => + ( + billing: null | import('~/types').BillingType, + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined + ) => billing?.products?.some((product) => product.addons?.some((addon) => addon.type === productWithFeature?.type) ), ], featureInfo: [ (s) => [s.productWithFeature], - (productWithFeature) => productWithFeature?.features.find((f) => f.key === props.feature), + (productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined) => + productWithFeature?.features.find((f) => f.key === props.feature), ], featureAvailableOnOrg: [ (s) => [s.user, (_, props) => props.feature], - (_user, feature) => { + (_user: null | import('~/types').UserType, feature) => { return values.availableFeature(feature) }, ], minimumPlanWithFeature: [ (s) => [s.productWithFeature], - (productWithFeature) => + (productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined) => productWithFeature?.plans.find((plan) => plan.features?.some((f) => f.key === props.feature)), ], nextPlanWithFeature: [ (s) => [s.productWithFeature], - (productWithFeature) => { + (productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined) => { const currentPlanIndex = productWithFeature?.plans.findIndex((plan) => plan.current_plan) if (currentPlanIndex === undefined || currentPlanIndex < 0) { return null @@ -117,7 +215,8 @@ export const payGateMiniLogic = kea([ ], featureInfoOnNextPlan: [ (s) => [s.nextPlanWithFeature], - (nextPlanWithFeature) => nextPlanWithFeature?.features.find((f) => f.key === props.feature), + (nextPlanWithFeature: null | import('~/types').BillingPlanType | undefined) => + nextPlanWithFeature?.features.find((f) => f.key === props.feature), ], gateVariant: [ (s) => [ @@ -127,7 +226,13 @@ export const payGateMiniLogic = kea([ (_, props) => props.feature, (_, props) => props.currentUsage, ], - (billingLoading, hasAvailableFeature, minimumPlanWithFeature, feature, currentUsage) => { + ( + billingLoading: boolean, + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean, + minimumPlanWithFeature: import('~/types').BillingPlanType | undefined, + feature, + currentUsage + ) => { if (hasAvailableFeature(feature, currentUsage)) { return null } @@ -145,7 +250,11 @@ export const payGateMiniLogic = kea([ ], ctaLink: [ (s) => [s.gateVariant, s.productWithFeature, s.featureInfo], - (gateVariant, productWithFeature, featureInfo) => { + ( + gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null, + productWithFeature: BillingProductV2AddonType | BillingProductV2Type | undefined, + featureInfo: import('~/types').BillingFeatureType | undefined + ) => { // product activation is already handled in the startPaymentEntryFlow, // ctaLink is used only when isPaymentEntryFlow is false if (gateVariant === 'add-card') { @@ -160,7 +269,7 @@ export const payGateMiniLogic = kea([ ], ctaLabel: [ (s) => [s.gateVariant, s.isPaymentEntryFlow], - (gateVariant, isPaymentEntryFlow) => { + (gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null, isPaymentEntryFlow: boolean) => { if (gateVariant === 'contact-sales') { return 'Contact sales' } @@ -178,7 +287,11 @@ export const payGateMiniLogic = kea([ ], isPaymentEntryFlow: [ (s) => [s.gateVariant, s.isAddonProduct, s.billing], - (gateVariant, isAddonProduct, billing): boolean => { + ( + gateVariant: 'add-card' | 'contact-sales' | 'move-to-cloud' | null, + isAddonProduct: boolean | undefined, + billing: null | import('~/types').BillingType + ): boolean => { // Show payment entry flow only for free customers trying to upgrade to a paid plan // to use core features (not addons) return gateVariant === 'add-card' && !isAddonProduct && billing?.subscription_level === 'free' diff --git a/frontend/src/lib/components/ProductSetup/globalSetupLogic.ts b/frontend/src/lib/components/ProductSetup/globalSetupLogic.ts index dfa7dfe5ccbf..2d3125146906 100644 --- a/frontend/src/lib/components/ProductSetup/globalSetupLogic.ts +++ b/frontend/src/lib/components/ProductSetup/globalSetupLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, listeners, path, reducers, selectors } from 'kea' import { subscriptions } from 'kea-subscriptions' import posthog from 'posthog-js' @@ -9,9 +9,70 @@ import { teamLogic as globalTeamLogic } from 'scenes/teamLogic' import { ProductKey } from '~/queries/schema/schema-general' import { ActivationTaskStatus } from '~/types' -import type { globalSetupLogicType } from './globalSetupLogicType' +import type { AvailableSetupTaskIdsEnumApi } from '../../../generated/core/api.schemas' import { PRODUCTS_WITH_SETUP } from './productSetupRegistry' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface globalSetupLogicValues { + activeSceneProductKey: ProductKey | null; // sceneLogic + availableProducts: ProductKey[]; + highlightSelector: string | null; + isGlobalModalOpen: boolean; + isProductSelectionLocked: boolean; + optimisticTaskStatuses: Record; + sceneHasNoSetup: boolean; + sceneProductKey: ProductKey | null; + selectedProduct: ProductKey; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface globalSetupLogicActions { + clearHighlightSelector: () => { + value: true; + }; + clearOptimisticTaskStatuses: (taskIds: SetupTaskId[]) => { + taskIds: AvailableSetupTaskIdsEnumApi[]; + }; + closeGlobalSetup: () => { + value: true; + }; + markTaskAsCompleted: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[]; + }; + markTaskAsSkipped: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[]; + }; + openGlobalSetup: () => { + value: true; + }; + setHighlightSelector: (selector: string | null) => { + selector: string | null; + }; + setOptimisticTaskStatuses: (statuses: Record) => { + statuses: Record; + }; + setSelectedProduct: (productKey: ProductKey) => { + productKey: ProductKey; + }; + unmarkTaskAsCompleted: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[]; + }; + unmarkTaskAsSkipped: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[]; + }; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface globalSetupLogicMeta { + __keaTypeGenInternalSelectorTypes: { + sceneProductKey: (activeSceneProductKey: ProductKey | null) => ProductKey | null; + sceneHasNoSetup: (activeSceneProductKey: ProductKey | null) => boolean; + isProductSelectionLocked: (sceneProductKey: ProductKey | null) => boolean; + }; +} + +export type globalSetupLogicType = MakeLogicType, globalSetupLogicMeta>; + /** * Global setup logic - the single source of truth for task completion and UI state. * @@ -97,7 +158,7 @@ export const globalSetupLogic = kea([ // Used for auto-selecting the product in the popover sceneProductKey: [ (s) => [s.activeSceneProductKey], - (activeSceneProductKey): ProductKey | null => { + (activeSceneProductKey: ProductKey | null): ProductKey | null => { if (activeSceneProductKey && PRODUCTS_WITH_SETUP.includes(activeSceneProductKey)) { return activeSceneProductKey } @@ -108,12 +169,15 @@ export const globalSetupLogic = kea([ // Used to hide the Quick Start button on scenes for products without onboarding sceneHasNoSetup: [ (s) => [s.activeSceneProductKey], - (activeSceneProductKey): boolean => { + (activeSceneProductKey: ProductKey | null): boolean => { return activeSceneProductKey !== null && !PRODUCTS_WITH_SETUP.includes(activeSceneProductKey) }, ], // Whether the product selection is locked to the current scene - isProductSelectionLocked: [(s) => [s.sceneProductKey], (sceneProductKey) => sceneProductKey !== null], + isProductSelectionLocked: [ + (s) => [s.sceneProductKey], + (sceneProductKey: ProductKey | null) => sceneProductKey !== null, + ], }), // NOTE: Not using `connect` here because the teamLogic might not have mounted yet // by the time this logic is mounted diff --git a/frontend/src/lib/components/ProductSetup/productSetupLogic.ts b/frontend/src/lib/components/ProductSetup/productSetupLogic.ts index 76a6506c6e96..7bbeee5f0d51 100644 --- a/frontend/src/lib/components/ProductSetup/productSetupLogic.ts +++ b/frontend/src/lib/components/ProductSetup/productSetupLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { router } from 'kea-router' import posthog from 'posthog-js' @@ -11,11 +11,13 @@ import { teamLogic } from 'scenes/teamLogic' import { ProductKey } from '~/queries/schema/schema-general' import { ActivationTaskStatus } from '~/types' +import type { AvailableSetupTaskIdsEnumApi } from '../../../generated/core/api.schemas' +import type { TeamPublicType, TeamType } from '../../../types' import { reverseProxyCheckerLogic } from '../ReverseProxyChecker/reverseProxyCheckerLogic' import { globalSetupLogic } from './globalSetupLogic' -import type { productSetupLogicType } from './productSetupLogicType' import { getProductSetupConfig, getTasksForProduct } from './productSetupRegistry' import type { SetupTaskWithState } from './types' +import type { ProductSetupConfig, SetupTask } from './types' export interface ProductSetupLogicProps { productKey: ProductKey @@ -23,6 +25,124 @@ export interface ProductSetupLogicProps { const DISMISSED_STORAGE_KEY = 'posthog_product_setup_dismissed' +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface productSetupLogicValues { + optimisticTaskStatuses: Record // globalSetupLogic + isCurrentOrganizationNew: boolean // organizationLogic + isCloudOrDev: boolean | undefined // preflightLogic + hasReverseProxy: boolean | null // reverseProxyCheckerLogic + currentTeam: TeamPublicType | TeamType | null // teamLogic + activeTasks: SetupTaskWithState[] + allTasks: SetupTask[] + completedCount: number + completedTasks: SetupTaskWithState[] + completionPercent: number + firstAvailableTask: SetupTaskWithState | null + isDismissed: boolean + isModalOpen: boolean + isSetupComplete: boolean + productConfig: ProductSetupConfig | null + remainingCount: number + savedOnboardingTasks: Record + shouldShowSetup: boolean + showCelebration: boolean + skippedTasks: SetupTaskWithState[] + tasksWithState: SetupTaskWithState[] + totalTasks: number +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface productSetupLogicActions { + closeGlobalSetup: () => { + value: true + } // globalSetupLogic + markTaskAsCompleted: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[] + } // globalSetupLogic + markTaskAsSkipped: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[] + } // globalSetupLogic + openGlobalSetup: () => { + value: true + } // globalSetupLogic + setHighlightSelector: (selector: string | null) => { + selector: string | null + } // globalSetupLogic + unmarkTaskAsCompleted: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[] + } // globalSetupLogic + unmarkTaskAsSkipped: (taskIdOrIds: SetupTaskId | SetupTaskId[]) => { + taskIdOrIds: AvailableSetupTaskIdsEnumApi | AvailableSetupTaskIdsEnumApi[] + } // globalSetupLogic + showInviteModal: () => { + value: true + } // inviteLogic + loadHasReverseProxy: () => any // reverseProxyCheckerLogic + closeSetupModal: () => { + value: true + } + dismissSetup: () => { + value: true + } + loadCompletionData: () => { + value: true + } + openSetupModal: () => { + value: true + } + runTask: (taskId: SetupTaskId) => { + taskId: AvailableSetupTaskIdsEnumApi + } + setExpandedTaskId: (taskId: SetupTaskId | null) => { + taskId: AvailableSetupTaskIdsEnumApi | null + } + setShowCelebration: (show: boolean) => { + show: boolean + } + undismissSetup: () => { + value: true + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface productSetupLogicMeta { + key: ProductKey + __keaTypeGenInternalSelectorTypes: { + productConfig: (productKey: ProductKey) => ProductSetupConfig | null + allTasks: (productKey: ProductKey, isCloudOrDev: boolean | undefined) => SetupTask[] + savedOnboardingTasks: ( + currentTeam: TeamPublicType | TeamType | null, + optimisticTaskStatuses: Record + ) => Record + tasksWithState: ( + allTasks: SetupTask[], + savedOnboardingTasks: Record, + hasReverseProxy: boolean | null + ) => SetupTaskWithState[] + activeTasks: (tasksWithState: SetupTaskWithState[]) => SetupTaskWithState[] + completedTasks: (tasksWithState: SetupTaskWithState[]) => SetupTaskWithState[] + skippedTasks: (tasksWithState: SetupTaskWithState[]) => SetupTaskWithState[] + totalTasks: (tasksWithState: SetupTaskWithState[]) => number + completedCount: (completedTasks: SetupTaskWithState[], skippedTasks: SetupTaskWithState[]) => number + remainingCount: (activeTasks: SetupTaskWithState[]) => number + completionPercent: (completedCount: number, totalTasks: number) => number + isSetupComplete: (remainingCount: number) => boolean + shouldShowSetup: ( + isSetupComplete: boolean, + productConfig: ProductSetupConfig | null, + isCurrentOrganizationNew: boolean + ) => boolean + firstAvailableTask: (activeTasks: SetupTaskWithState[]) => SetupTaskWithState | null + } +} + +export type productSetupLogicType = MakeLogicType< + productSetupLogicValues, + productSetupLogicActions, + ProductSetupLogicProps, + productSetupLogicMeta +> + /** * Product setup logic - handles product-specific state and UI for the setup experience. * @@ -107,10 +227,10 @@ export const productSetupLogic = kea([ ], })), selectors({ - productConfig: [(_, p) => [p.productKey], (productKey) => getProductSetupConfig(productKey)], + productConfig: [(_, p) => [p.productKey], (productKey: ProductKey) => getProductSetupConfig(productKey)], allTasks: [ (s, p) => [p.productKey, s.isCloudOrDev], - (productKey, isCloudOrDev) => { + (productKey: ProductKey, isCloudOrDev: boolean | undefined) => { const tasks = getTasksForProduct(productKey) if (!isCloudOrDev) { return tasks.filter((task) => task.id !== SetupTaskId.SetUpReverseProxy) @@ -122,14 +242,21 @@ export const productSetupLogic = kea([ // null in optimistic means "unmarked" - takes priority over saved status savedOnboardingTasks: [ (s) => [s.currentTeam, s.optimisticTaskStatuses], - (currentTeam, optimisticTaskStatuses): Record => ({ + ( + currentTeam: null | import('~/types').TeamPublicType | import('~/types').TeamType, + optimisticTaskStatuses: Record + ): Record => ({ ...currentTeam?.onboarding_tasks, ...optimisticTaskStatuses, }), ], tasksWithState: [ (s) => [s.allTasks, s.savedOnboardingTasks, s.hasReverseProxy], - (allTasks, savedOnboardingTasks, hasReverseProxy): SetupTaskWithState[] => { + ( + allTasks: import('lib/components/ProductSetup').SetupTask[], + savedOnboardingTasks: Record, + hasReverseProxy: boolean | null + ): SetupTaskWithState[] => { return allTasks.map((task) => { // Check for auto-completion conditions let isAutoCompleted = false @@ -166,18 +293,27 @@ export const productSetupLogic = kea([ }) }, ], - activeTasks: [(s) => [s.tasksWithState], (tasks) => tasks.filter((task) => !task.completed && !task.skipped)], - completedTasks: [(s) => [s.tasksWithState], (tasks) => tasks.filter((task) => task.completed)], - skippedTasks: [(s) => [s.tasksWithState], (tasks) => tasks.filter((task) => task.skipped)], - totalTasks: [(s) => [s.tasksWithState], (tasks) => tasks.length], + activeTasks: [ + (s) => [s.tasksWithState], + (tasks: SetupTaskWithState[]) => tasks.filter((task) => !task.completed && !task.skipped), + ], + completedTasks: [ + (s) => [s.tasksWithState], + (tasks: SetupTaskWithState[]) => tasks.filter((task) => task.completed), + ], + skippedTasks: [ + (s) => [s.tasksWithState], + (tasks: SetupTaskWithState[]) => tasks.filter((task) => task.skipped), + ], + totalTasks: [(s) => [s.tasksWithState], (tasks: SetupTaskWithState[]) => tasks.length], completedCount: [ (s) => [s.completedTasks, s.skippedTasks], (completed: SetupTaskWithState[], skipped: SetupTaskWithState[]) => completed.length + skipped.length, ], - remainingCount: [(s) => [s.activeTasks], (tasks) => tasks.length], + remainingCount: [(s) => [s.activeTasks], (tasks: SetupTaskWithState[]) => tasks.length], completionPercent: [ (s) => [s.completedCount, s.totalTasks], - (completed, total) => { + (completed: number, total: number) => { if (total === 0) { return 100 } @@ -185,10 +321,14 @@ export const productSetupLogic = kea([ return percent >= 5 ? percent : 5 // Min 5% for visibility }, ], - isSetupComplete: [(s) => [s.remainingCount], (remaining) => remaining === 0], + isSetupComplete: [(s) => [s.remainingCount], (remaining: number) => remaining === 0], shouldShowSetup: [ (s) => [s.isSetupComplete, s.productConfig, s.isCurrentOrganizationNew], - (isComplete, config, isNewOrg) => { + ( + isComplete: boolean, + config: null | import('lib/components/ProductSetup').ProductSetupConfig, + isNewOrg: boolean + ) => { // Don't show if no valid config if (!config || !config.title) { return false @@ -201,7 +341,10 @@ export const productSetupLogic = kea([ return !isComplete }, ], - firstAvailableTask: [(s) => [s.activeTasks], (tasks) => tasks.find((t) => !t.lockedReason) ?? null], + firstAvailableTask: [ + (s) => [s.activeTasks], + (tasks: SetupTaskWithState[]) => tasks.find((t) => !t.lockedReason) ?? null, + ], }), listeners(({ props, actions, values }) => ({ runTask: async ({ taskId }) => { diff --git a/frontend/src/lib/components/PropertiesTimeline/propertiesTimelineLogic.ts b/frontend/src/lib/components/PropertiesTimeline/propertiesTimelineLogic.ts index e9ee86d08209..70af806311f9 100644 --- a/frontend/src/lib/components/PropertiesTimeline/propertiesTimelineLogic.ts +++ b/frontend/src/lib/components/PropertiesTimeline/propertiesTimelineLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, key, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, path, props, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import posthog from 'posthog-js' @@ -10,8 +10,6 @@ import { teamLogic } from 'scenes/teamLogic' import { Properties } from '~/legacy-plugin-scaffold' import { ActorType, PropertiesTimelineFilterType } from '~/types' -import type { propertiesTimelineLogicType } from './propertiesTimelineLogicType' - export interface PropertiesTimelinePoint { timestamp: Dayjs properties: Properties @@ -36,6 +34,57 @@ export interface PropertiesTimelineProps { filter: PropertiesTimelineFilterType } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertiesTimelineLogicValues { + currentTeamId: number | null // teamLogic + timezone: string // teamLogic + crucialPropertyKeys: (keyof Properties)[] + dateRange: [Dayjs, Dayjs] | null + points: PropertiesTimelinePoint[] + result: RawPropertiesTimelineResult | null + resultLoading: boolean + selectedPointIndex: number | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertiesTimelineLogicActions { + loadResult: () => any + loadResultFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadResultSuccess: ( + result: RawPropertiesTimelineResult, + payload?: any + ) => { + result: RawPropertiesTimelineResult + payload?: any + } + setSelectedPointIndex: (index: number | null) => { + index: number | null + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertiesTimelineLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + points: (result: RawPropertiesTimelineResult | null, timezone: string) => PropertiesTimelinePoint[] + crucialPropertyKeys: (result: RawPropertiesTimelineResult | null) => (keyof Properties)[] + dateRange: (result: RawPropertiesTimelineResult | null, timezone: string) => [Dayjs, Dayjs] | null + } +} + +export type propertiesTimelineLogicType = MakeLogicType< + propertiesTimelineLogicValues, + propertiesTimelineLogicActions, + PropertiesTimelineProps, + propertiesTimelineLogicMeta +> + export const propertiesTimelineLogic = kea([ path(['lib', 'components', 'PropertiesTimeline', 'propertiesTimelineLogic']), props({} as PropertiesTimelineProps), @@ -90,7 +139,7 @@ export const propertiesTimelineLogic = kea([ selectors({ points: [ (s) => [s.result, s.timezone], - (result, timezone) => + (result: RawPropertiesTimelineResult | null, timezone: string) => result ? result.points.map( (point): PropertiesTimelinePoint => ({ @@ -103,11 +152,12 @@ export const propertiesTimelineLogic = kea([ ], crucialPropertyKeys: [ (s) => [s.result], - (result): (keyof Properties)[] => (result ? result.crucial_property_keys : []), + (result: RawPropertiesTimelineResult | null): (keyof Properties)[] => + result ? result.crucial_property_keys : [], ], dateRange: [ (s) => [s.result, s.timezone], - (result, timezone): [Dayjs, Dayjs] | null => + (result: RawPropertiesTimelineResult | null, timezone: string): [Dayjs, Dayjs] | null => result && [ dayjsUtcToTimezone(result.effective_date_from, timezone), dayjsUtcToTimezone(result.effective_date_to, timezone), diff --git a/frontend/src/lib/components/PropertyFilters/components/distinctIdSelectLogic.ts b/frontend/src/lib/components/PropertyFilters/components/distinctIdSelectLogic.ts index 7b86ead4ec49..3ccf9551909c 100644 --- a/frontend/src/lib/components/PropertyFilters/components/distinctIdSelectLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/distinctIdSelectLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' @@ -7,8 +7,6 @@ import { teamLogic } from 'scenes/teamLogic' import { PersonType } from '~/types' -import type { distinctIdSelectLogicType } from './distinctIdSelectLogicType' - export interface DistinctIdSelectLogicProps { /** Stable per-instance key so two pickers mounted side-by-side don't share state. */ instanceKey: string @@ -36,6 +34,72 @@ export async function resolveDistinctIdNames(distinctIds: string[]): Promise + searchQuery: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface distinctIdSelectLogicActions { + loadPersons: ({ search }: { search?: string }) => { + search?: string + } + loadPersonsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadPersonsSuccess: ( + persons: PersonType[], + payload?: { + search?: string + } + ) => { + persons: PersonType[] + payload?: { + search?: string + } + } + setResolvedNames: (names: Record) => { + names: Record + } + setSearchQuery: (query: string) => { + query: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface distinctIdSelectLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + mergedOptions: ( + persons: PersonType[], + resolvedNames: Record, + value: string[] + ) => { + key: string + label: string + }[] + } +} + +export type distinctIdSelectLogicType = MakeLogicType< + distinctIdSelectLogicValues, + distinctIdSelectLogicActions, + DistinctIdSelectLogicProps, + distinctIdSelectLogicMeta +> + export const distinctIdSelectLogic = kea([ props({} as DistinctIdSelectLogicProps), key((props) => props.instanceKey), diff --git a/frontend/src/lib/components/PropertyFilters/components/groupKeySelectLogic.ts b/frontend/src/lib/components/PropertyFilters/components/groupKeySelectLogic.ts index 73e875677c98..f2e09a41e68b 100644 --- a/frontend/src/lib/components/PropertyFilters/components/groupKeySelectLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/groupKeySelectLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, reducers } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers } from 'kea' import { loaders } from 'kea-loaders' import posthog from 'posthog-js' @@ -9,8 +9,6 @@ import { teamLogic } from 'scenes/teamLogic' import { Group, GroupTypeIndex } from '~/types' -import type { groupKeySelectLogicType } from './groupKeySelectLogicType' - export interface GroupKeySelectLogicProps { groupTypeIndex: GroupTypeIndex value: string[] @@ -67,6 +65,58 @@ export async function resolveGroupNames( return names } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupKeySelectLogicValues { + currentTeamId: number | null // teamLogic + groups: Group[] + groupsLoading: boolean + resolvedNames: Record + searchQuery: string +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupKeySelectLogicActions { + loadGroups: ({ search }: { search?: string }) => { + search?: string + } + loadGroupsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadGroupsSuccess: ( + groups: Group[], + payload?: { + search?: string + } + ) => { + groups: Group[] + payload?: { + search?: string + } + } + setResolvedNames: (names: Record) => { + names: Record + } + setSearchQuery: (query: string) => { + query: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupKeySelectLogicMeta { + key: string +} + +export type groupKeySelectLogicType = MakeLogicType< + groupKeySelectLogicValues, + groupKeySelectLogicActions, + GroupKeySelectLogicProps, + groupKeySelectLogicMeta +> + export const groupKeySelectLogic = kea([ props({} as GroupKeySelectLogicProps), key((props) => `${props.groupTypeIndex}`), diff --git a/frontend/src/lib/components/PropertyFilters/components/groupKeyTooltipLogic.ts b/frontend/src/lib/components/PropertyFilters/components/groupKeyTooltipLogic.ts index 0a536426589f..f5f27dc6e04b 100644 --- a/frontend/src/lib/components/PropertyFilters/components/groupKeyTooltipLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/groupKeyTooltipLogic.ts @@ -1,4 +1,4 @@ -import { afterMount, connect, kea, key, path, props } from 'kea' +import { MakeLogicType, afterMount, connect, kea, key, path, props } from 'kea' import { loaders } from 'kea-loaders' import { teamLogic } from 'scenes/teamLogic' @@ -6,7 +6,6 @@ import { teamLogic } from 'scenes/teamLogic' import { Group, GroupTypeIndex } from '~/types' import { findGroups } from './groupKeySelectLogic' -import type { groupKeyTooltipLogicType } from './groupKeyTooltipLogicType' export interface GroupKeyTooltipLogicProps { groupTypeIndex: GroupTypeIndex @@ -51,6 +50,44 @@ async function cachedFindGroup( return null } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupKeyTooltipLogicValues { + currentTeamId: number | null // teamLogic + group: Group | null + groupLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupKeyTooltipLogicActions { + loadGroup: () => any + loadGroupFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadGroupSuccess: ( + group: Group | null, + payload?: any + ) => { + group: Group | null + payload?: any + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface groupKeyTooltipLogicMeta { + key: string +} + +export type groupKeyTooltipLogicType = MakeLogicType< + groupKeyTooltipLogicValues, + groupKeyTooltipLogicActions, + GroupKeyTooltipLogicProps, + groupKeyTooltipLogicMeta +> + export const groupKeyTooltipLogic = kea([ props({} as GroupKeyTooltipLogicProps), key((props) => `${props.groupTypeIndex}-${props.groupKey}`), diff --git a/frontend/src/lib/components/PropertyFilters/components/propertyFilterBetweenLogic.ts b/frontend/src/lib/components/PropertyFilters/components/propertyFilterBetweenLogic.ts index 413f9b77c1ef..9a59b4736b7e 100644 --- a/frontend/src/lib/components/PropertyFilters/components/propertyFilterBetweenLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/propertyFilterBetweenLogic.ts @@ -1,9 +1,7 @@ -import { actions, kea, key, listeners, path, props, propsChanged, reducers } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, propsChanged, reducers } from 'kea' import { PropertyFilterBaseValue, PropertyFilterValue } from '~/types' -import type { propertyFilterBetweenLogicType } from './propertyFilterBetweenLogicType' - export interface PropertyFilterBetweenLogicProps { key: string value: PropertyFilterValue @@ -23,6 +21,34 @@ function valuesMatch(a?: PropertyFilterBaseValue, b?: PropertyFilterBaseValue): return Number.isNaN(a) === Number.isNaN(b) ? true : a === b } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertyFilterBetweenLogicValues { + localMax: number | null + localMin: number | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertyFilterBetweenLogicActions { + setLocalMax: (value: number | null) => { + value: number | null + } + setLocalMin: (value: number | null) => { + value: number | null + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertyFilterBetweenLogicMeta { + key: string +} + +export type propertyFilterBetweenLogicType = MakeLogicType< + propertyFilterBetweenLogicValues, + propertyFilterBetweenLogicActions, + PropertyFilterBetweenLogicProps, + propertyFilterBetweenLogicMeta +> + export const propertyFilterBetweenLogic = kea([ path(['lib', 'components', 'PropertyFilters', 'components', 'propertyFilterBetweenLogic']), props({} as PropertyFilterBetweenLogicProps), diff --git a/frontend/src/lib/components/PropertyFilters/components/propertyValueLogic.ts b/frontend/src/lib/components/PropertyFilters/components/propertyValueLogic.ts index 00e005fc1d59..cd293eb7ac8f 100644 --- a/frontend/src/lib/components/PropertyFilters/components/propertyValueLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/propertyValueLogic.ts @@ -1,23 +1,53 @@ -import { connect, kea, key, path, props, selectors } from 'kea' +import { MakeLogicType, connect, kea, key, path, props, selectors } from 'kea' import { propertyDefinitionsModel } from '~/models/propertyDefinitionsModel' import { PropertyDefinitionType } from '~/types' -import type { propertyValueLogicType } from './propertyValueLogicType' +import type { Option } from '../../../../models/propertyDefinitionsModel' export interface PropertyValueLogicProps { propertyKey: string type: PropertyDefinitionType } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertyValueLogicValues { + options: Record // propertyDefinitionsModel + isRefreshing: boolean + propertyOption: Option +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertyValueLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + propertyOption: (options: Record) => Option + isRefreshing: (propertyOption: Option) => boolean + } +} + +export type propertyValueLogicType = MakeLogicType< + propertyValueLogicValues, + {}, + PropertyValueLogicProps, + propertyValueLogicMeta +> + export const propertyValueLogic = kea([ path(['lib', 'components', 'PropertyFilters', 'propertyValueLogic']), props({} as PropertyValueLogicProps), key((props) => `${props.type}/${props.propertyKey}`), connect(() => ({ values: [propertyDefinitionsModel, ['options']] })), selectors(({ props }) => ({ - propertyOption: [(s) => [s.options], (options) => options[props.propertyKey]], + propertyOption: [ + (s) => [s.options], + (options: Record) => options[props.propertyKey], + ], /** Whether a background cache refresh is currently in progress for this property. */ - isRefreshing: [(s) => [s.propertyOption], (propertyOption): boolean => propertyOption?.refreshing ?? false], + isRefreshing: [ + (s) => [s.propertyOption], + (propertyOption: import('~/models/propertyDefinitionsModel').Option): boolean => + propertyOption?.refreshing ?? false, + ], })), ]) diff --git a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts index e78eb0b4a050..61d2edad2203 100644 --- a/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/components/taxonomicPropertyFilterLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { TaxonomicPropertyFilterLogicProps } from 'lib/components/PropertyFilters/types' import { isValidPropertyFilter } from 'lib/components/PropertyFilters/utils' @@ -31,7 +31,60 @@ import { PropertyOperator, } from '~/types' -import type { taxonomicPropertyFilterLogicType } from './taxonomicPropertyFilterLogicType' +import type { PropertyDefinitionType, PropertyType } from '../../../../types' + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface taxonomicPropertyFilterLogicValues { + describeProperty: ( + s: TaxonomicFilterValue, + type: PropertyDefinitionType, + groupTypeIndex?: number + ) => PropertyType | null // propertyDefinitionsModel + taxonomicGroups: TaxonomicFilterGroup[] // taxonomicFilterLogic + activeTaxonomicGroup: TaxonomicFilterGroup | undefined + dropdownOpen: boolean + filter: AnyPropertyFilter | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface taxonomicPropertyFilterLogicActions { + closeDropdown: () => { + value: true + } + openDropdown: () => { + value: true + } + selectItem: ( + taxonomicGroup: TaxonomicFilterGroup, + propertyKey?: TaxonomicFilterValue, + itemPropertyFilterType?: PropertyFilterType, + item?: any + ) => { + item: any + itemPropertyFilterType: PropertyFilterType | undefined + propertyKey: TaxonomicFilterValue | undefined + taxonomicGroup: TaxonomicFilterGroup + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface taxonomicPropertyFilterLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + filter: (filters: AnyPropertyFilter[], filterIndex: number) => AnyPropertyFilter | null + activeTaxonomicGroup: ( + filter: AnyPropertyFilter | null, + taxonomicGroups: TaxonomicFilterGroup[] + ) => TaxonomicFilterGroup | undefined + } +} + +export type taxonomicPropertyFilterLogicType = MakeLogicType< + taxonomicPropertyFilterLogicValues, + taxonomicPropertyFilterLogicActions, + TaxonomicPropertyFilterLogicProps, + taxonomicPropertyFilterLogicMeta +> export const taxonomicPropertyFilterLogic = kea([ props({} as TaxonomicPropertyFilterLogicProps), @@ -80,12 +133,12 @@ export const taxonomicPropertyFilterLogic = kea [p.filters, p.filterIndex], - (filters, filterIndex): AnyPropertyFilter | null => + (filters: AnyPropertyFilter[], filterIndex: number): AnyPropertyFilter | null => filters[filterIndex] ? sanitizePropertyFilter(filters[filterIndex]) : null, ], activeTaxonomicGroup: [ (s) => [s.filter, s.taxonomicGroups], - (filter, groups): TaxonomicFilterGroup | undefined => { + (filter: AnyPropertyFilter | null, groups: TaxonomicFilterGroup[]): TaxonomicFilterGroup | undefined => { if (isAnyPropertyfilter(filter)) { const taxonomicGroupType = propertyFilterTypeToTaxonomicFilterType(filter) return groups.find((group) => group.type === taxonomicGroupType) diff --git a/frontend/src/lib/components/PropertyFilters/propertyFilterLogic.ts b/frontend/src/lib/components/PropertyFilters/propertyFilterLogic.ts index da4078161708..b987c2feb73b 100644 --- a/frontend/src/lib/components/PropertyFilters/propertyFilterLogic.ts +++ b/frontend/src/lib/components/PropertyFilters/propertyFilterLogic.ts @@ -1,5 +1,5 @@ import { deepEqual as equal } from 'fast-equals' -import { actions, kea, key, listeners, path, props, propsChanged, reducers, selectors } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, propsChanged, reducers, selectors } from 'kea' import { PropertyFilterLogicProps } from 'lib/components/PropertyFilters/types' import { @@ -37,7 +37,6 @@ const TAXONOMIC_GROUP_TYPE_TO_DISPLAY_NAME: Partial { + index: number; + }; + setFilter: (index: number, property: AnyPropertyFilter) => { + index: number; + property: AnyPropertyFilter; + }; + setFilters: (filters: AnyPropertyFilter[]) => { + filters: AnyPropertyFilter[]; + }; + update: () => { + value: true; + }; +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface propertyFilterLogicMeta { + key: string; + __keaTypeGenInternalSelectorTypes: { + filters: (_filtersState: FiltersState) => AnyPropertyFilter[]; + filterIds: (_filtersState: FiltersState) => number[]; + filledFilters: (filters: AnyPropertyFilter[]) => AnyPropertyFilter[]; + filtersWithNew: (filters: AnyPropertyFilter[]) => AnyPropertyFilter[]; + filterIdsWithNew: (filterIds: number[], _filtersState: FiltersState, filtersWithNew: AnyPropertyFilter[]) => number[]; + }; +} + +export type propertyFilterLogicType = MakeLogicType; + export const propertyFilterLogic = kea([ path((key) => ['lib', 'components', 'PropertyFilters', 'propertyFilterLogic', key]), props({} as PropertyFilterLogicProps), @@ -165,10 +205,10 @@ export const propertyFilterLogic = kea([ (state: FiltersState): AnyPropertyFilter[] => state.items.map((i) => i.filter), ], filterIds: [(s) => [s._filtersState], (state: FiltersState): number[] => state.items.map((i) => i._id)], - filledFilters: [(s) => [s.filters], (filters) => filters.filter(isValidPropertyFilter)], + filledFilters: [(s) => [s.filters], (filters: AnyPropertyFilter[]) => filters.filter(isValidPropertyFilter)], filtersWithNew: [ (s) => [s.filters], - (filters) => { + (filters: AnyPropertyFilter[]) => { if (filters.length === 0 || isValidPropertyFilter(filters[filters.length - 1])) { return [...filters, {} as AnyPropertyFilter] } diff --git a/frontend/src/lib/components/PropertyFilters/utils.test.ts b/frontend/src/lib/components/PropertyFilters/utils.test.ts index 4d377efdfba6..7f273ee49b6e 100644 --- a/frontend/src/lib/components/PropertyFilters/utils.test.ts +++ b/frontend/src/lib/components/PropertyFilters/utils.test.ts @@ -12,7 +12,7 @@ import { taxonomicFilterTypeToPropertyFilterType, } from 'lib/components/PropertyFilters/utils' -import { propertyDefinitionsModelType } from '~/models/propertyDefinitionsModelType' +import type { propertyDefinitionsModelType } from '~/models/propertyDefinitionsModel' import { BreakdownFilter } from '~/queries/schema/schema-general' import { diff --git a/frontend/src/lib/components/PropertyFilters/utils.ts b/frontend/src/lib/components/PropertyFilters/utils.ts index 285b56a058fc..d0f626270db9 100644 --- a/frontend/src/lib/components/PropertyFilters/utils.ts +++ b/frontend/src/lib/components/PropertyFilters/utils.ts @@ -9,7 +9,7 @@ import { } from 'lib/utils/operators' import { capitalizeFirstLetter } from 'lib/utils/strings' -import { propertyDefinitionsModelType } from '~/models/propertyDefinitionsModelType' +import type { propertyDefinitionsModelType } from '~/models/propertyDefinitionsModel' import { extractExpressionComment } from '~/queries/nodes/DataTable/utils' import { BreakdownFilter } from '~/queries/schema/schema-general' import { getCoreFilterDefinition } from '~/taxonomy/helpers' diff --git a/frontend/src/lib/components/QuickFilters/quickFilterFormLogic.ts b/frontend/src/lib/components/QuickFilters/quickFilterFormLogic.ts index 604a47176b96..bbc57f7d4233 100644 --- a/frontend/src/lib/components/QuickFilters/quickFilterFormLogic.ts +++ b/frontend/src/lib/components/QuickFilters/quickFilterFormLogic.ts @@ -1,5 +1,6 @@ -import { LogicWrapper, actions, connect, kea, key, listeners, path, props, selectors } from 'kea' +import { MakeLogicType, LogicWrapper, actions, connect, kea, key, listeners, path, props, selectors } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { propertyFilterTypeToPropertyDefinitionType } from 'lib/components/PropertyFilters/utils' import { uuid } from 'lib/utils/dom' @@ -7,7 +8,8 @@ import { uuid } from 'lib/utils/dom' import { propertyDefinitionsModel } from '~/models/propertyDefinitionsModel' import { PropertyFilterType, PropertyOperator, QuickFilter, QuickFilterOption } from '~/types' -import type { quickFilterFormLogicType } from './quickFilterFormLogicType' +import type { Option } from '../../../models/propertyDefinitionsModel' +import type { PropertyDefinitionType } from '../../../types' import { quickFiltersLogic } from './quickFiltersLogic' import { ModalView, QuickFiltersModalLogicProps, quickFiltersModalLogic } from './quickFiltersModalLogic' @@ -43,6 +45,128 @@ const trimValue = (value: string | string[] | null): string | string[] | null => export const operatorsWithoutValues = [PropertyOperator.IsSet, PropertyOperator.IsNotSet] +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFilterFormLogicValues { + propertyOptions: Record // propertyDefinitionsModel + isQuickFilterSubmitting: boolean + isQuickFilterValid: boolean + name: string + options: QuickFilterOption[] + propertyName: string + quickFilter: QuickFilterFormValues + quickFilterAllErrors: Record + quickFilterChanged: boolean + quickFilterErrors: DeepPartialMap + quickFilterHasErrors: boolean + quickFilterManualErrors: Record + quickFilterTouched: boolean + quickFilterTouches: Record + quickFilterValidationErrors: DeepPartialMap + showQuickFilterErrors: boolean + suggestions: any[] +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFilterFormLogicActions { + loadPropertyValues: (payload: { + endpoint: string | undefined + eventNames?: string[] + newInput: string | undefined + properties?: { + key: string + values: string | string[] + }[] + propertyKey: string + refresh?: string + type: PropertyDefinitionType + }) => { + endpoint: string | undefined + eventNames?: string[] | undefined + newInput: string | undefined + properties?: + | { + key: string + values: string | string[] + }[] + | undefined + propertyKey: string + refresh?: string | undefined + type: PropertyDefinitionType + } // propertyDefinitionsModel + closeModal: () => { + value: true + } // quickFiltersModalLogic + setView: (view: ModalView) => { + view: ModalView + } // quickFiltersModalLogic + addOption: () => { + value: true + } + removeOption: (index: number) => { + index: number + } + resetQuickFilter: (values?: QuickFilterFormValues) => { + values?: QuickFilterFormValues + } + setQuickFilterManualErrors: (errors: Record) => { + errors: Record + } + setQuickFilterValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setQuickFilterValues: (values: DeepPartial) => { + values: DeepPartial + } + submitQuickFilter: () => { + value: boolean + } + submitQuickFilterFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitQuickFilterRequest: (quickFilter: QuickFilterFormValues) => { + quickFilter: QuickFilterFormValues + } + submitQuickFilterSuccess: (quickFilter: QuickFilterFormValues) => { + quickFilter: QuickFilterFormValues + } + touchQuickFilterField: (key: string) => { + key: string + } + updateOption: ( + index: number, + updates: Partial + ) => { + index: number + updates: Partial + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFilterFormLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + name: (quickFilter: QuickFilterFormValues) => string + propertyName: (quickFilter: QuickFilterFormValues) => string + options: (quickFilter: QuickFilterFormValues) => QuickFilterOption[] + suggestions: (propertyName: string, propertyOptions: Record) => any[] + } +} + +export type quickFilterFormLogicType = MakeLogicType< + quickFilterFormLogicValues, + quickFilterFormLogicActions, + QuickFilterFormLogicProps, + quickFilterFormLogicMeta +> + export const quickFilterFormLogic: LogicWrapper = kea([ path(['lib', 'components', 'QuickFilters', 'quickFilterFormLogic']), props({} as QuickFilterFormLogicProps), @@ -143,12 +267,15 @@ export const quickFilterFormLogic: LogicWrapper = kea< })), selectors({ - name: [(s) => [s.quickFilter], (quickFilter) => quickFilter.name], - propertyName: [(s) => [s.quickFilter], (quickFilter) => quickFilter.propertyName], - options: [(s) => [s.quickFilter], (quickFilter) => quickFilter.options], + name: [(s) => [s.quickFilter], (quickFilter: QuickFilterFormValues) => quickFilter.name], + propertyName: [(s) => [s.quickFilter], (quickFilter: QuickFilterFormValues) => quickFilter.propertyName], + options: [(s) => [s.quickFilter], (quickFilter: QuickFilterFormValues) => quickFilter.options], suggestions: [ (s) => [s.propertyName, s.propertyOptions], - (propertyName, propertyOptions): any[] => { + ( + propertyName: string, + propertyOptions: Record + ): any[] => { return propertyName ? propertyOptions[propertyName]?.values || [] : [] }, ], diff --git a/frontend/src/lib/components/QuickFilters/quickFiltersLogic.ts b/frontend/src/lib/components/QuickFilters/quickFiltersLogic.ts index ebddc5952111..4bd28a75101d 100644 --- a/frontend/src/lib/components/QuickFilters/quickFiltersLogic.ts +++ b/frontend/src/lib/components/QuickFilters/quickFiltersLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, kea, key, path, props } from 'kea' +import { MakeLogicType, actions, afterMount, kea, key, path, props } from 'kea' import { loaders } from 'kea-loaders' import posthog from 'posthog-js' @@ -10,12 +10,120 @@ import { QuickFilterContext } from '~/queries/schema/schema-general' import { QuickFilter } from '~/types' import { QuickFiltersEvents } from './consts' -import type { quickFiltersLogicType } from './quickFiltersLogicType' export interface QuickFiltersLogicProps { context: QuickFilterContext } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersLogicValues { + quickFilters: QuickFilter[] + quickFiltersLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersLogicActions { + createFilter: (payload: Pick) => { + payload: Pick + } + createFilterFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + createFilterSuccess: ( + quickFilters: QuickFilter[], + payload?: { + payload: Pick + } + ) => { + quickFilters: QuickFilter[] + payload?: { + payload: Pick + } + } + deleteFilter: (id: string) => { + id: string + } + deleteFilterFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + deleteFilterSuccess: ( + quickFilters: QuickFilter[], + payload?: { + id: string + } + ) => { + quickFilters: QuickFilter[] + payload?: { + id: string + } + } + filterUpdated: (filter: QuickFilter) => { + filter: QuickFilter + } + loadQuickFilters: () => any + loadQuickFiltersFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadQuickFiltersSuccess: ( + quickFilters: QuickFilter[], + payload?: any + ) => { + quickFilters: QuickFilter[] + payload?: any + } + updateFilter: ( + id: string, + payload: Partial> + ) => { + id: string + payload: Partial> + } + updateFilterFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + updateFilterSuccess: ( + quickFilters: QuickFilter[], + payload?: { + id: string + payload: Partial> + } + ) => { + quickFilters: QuickFilter[] + payload?: { + id: string + payload: Partial> + } + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersLogicMeta { + key: QuickFilterContext +} + +export type quickFiltersLogicType = MakeLogicType< + quickFiltersLogicValues, + quickFiltersLogicActions, + QuickFiltersLogicProps, + quickFiltersLogicMeta +> + export const quickFiltersLogic = kea([ path(['lib', 'components', 'QuickFilters', 'quickFiltersLogic']), props({} as QuickFiltersLogicProps), diff --git a/frontend/src/lib/components/QuickFilters/quickFiltersModalLogic.ts b/frontend/src/lib/components/QuickFilters/quickFiltersModalLogic.ts index 03c9ccb8f27b..7f128655c09d 100644 --- a/frontend/src/lib/components/QuickFilters/quickFiltersModalLogic.ts +++ b/frontend/src/lib/components/QuickFilters/quickFiltersModalLogic.ts @@ -1,13 +1,25 @@ -import { LogicWrapper, actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { + MakeLogicType, + LogicWrapper, + actions, + connect, + kea, + key, + listeners, + path, + props, + reducers, + selectors, +} from 'kea' import posthog from 'posthog-js' import { LemonDialog } from '@posthog/lemon-ui' import { QuickFilter } from '~/types' +import type { QuickFilterContext } from '../../../queries/schema/schema-general' import { QuickFiltersEvents } from './consts' import { QuickFiltersLogicProps, quickFiltersLogic } from './quickFiltersLogic' -import type { quickFiltersModalLogicType } from './quickFiltersModalLogicType' export enum ModalView { List = 'list', @@ -19,6 +31,70 @@ export interface QuickFiltersModalLogicProps extends QuickFiltersLogicProps { onNewFilterCreated?: (filter: QuickFilter) => void } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersModalLogicValues { + quickFilters: QuickFilter[] // quickFiltersLogic + editedFilter: QuickFilter | null + filteredQuickFilters: QuickFilter[] + isModalOpen: boolean + modalTitle: string + searchQuery: string + view: ModalView +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersModalLogicActions { + deleteFilter: (id: string) => { + id: string + } // quickFiltersLogic + closeModal: () => { + value: true + } + confirmDelete: (id: string) => { + id: string + } + handleFormBack: () => { + value: true + } + newFilterCreated: (filter: QuickFilter) => { + filter: QuickFilter + } + openModal: () => { + value: true + } + setEditingFilter: (filter: QuickFilter | null) => { + filter: QuickFilter | null + } + setSearchQuery: (query: string) => { + query: string + } + setView: (view: ModalView) => { + view: ModalView + } + startAddNew: () => { + value: true + } + startEdit: (filter: QuickFilter) => { + filter: QuickFilter + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersModalLogicMeta { + key: QuickFilterContext + __keaTypeGenInternalSelectorTypes: { + modalTitle: (view: ModalView, editedFilter: QuickFilter | null) => string + filteredQuickFilters: (quickFilters: QuickFilter[], searchQuery: string) => QuickFilter[] + } +} + +export type quickFiltersModalLogicType = MakeLogicType< + quickFiltersModalLogicValues, + quickFiltersModalLogicActions, + QuickFiltersModalLogicProps, + quickFiltersModalLogicMeta +> + export const quickFiltersModalLogic: LogicWrapper = kea([ path(['lib', 'components', 'QuickFilters', 'quickFiltersModalLogic']), props({} as QuickFiltersModalLogicProps), diff --git a/frontend/src/lib/components/QuickFilters/quickFiltersSectionLogic.ts b/frontend/src/lib/components/QuickFilters/quickFiltersSectionLogic.ts index a4f15d860c69..aa1542dab73b 100644 --- a/frontend/src/lib/components/QuickFilters/quickFiltersSectionLogic.ts +++ b/frontend/src/lib/components/QuickFilters/quickFiltersSectionLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, key, listeners, path, props, reducers } from 'kea' +import { MakeLogicType, actions, connect, kea, key, listeners, path, props, reducers } from 'kea' import { actionToUrl, router, urlToAction } from 'kea-router' import posthog from 'posthog-js' @@ -7,8 +7,8 @@ import { quickFiltersLogic } from 'lib/components/QuickFilters' import { QuickFilterContext } from '~/queries/schema/schema-general' import { PropertyOperator, QuickFilterOption } from '~/types' +import type { QuickFilter } from '../../../types' import { QuickFiltersEvents } from './consts' -import type { quickFiltersSectionLogicType } from './quickFiltersSectionLogicType' const QUICK_FILTERS_URL_PARAM = 'quick_filters' @@ -77,6 +77,75 @@ const removeQuickFilter = ( return newState } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersSectionLogicValues { + quickFilters: QuickFilter[] // quickFiltersLogic + selectedQuickFilters: Record +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersSectionLogicActions { + deleteFilter: (id: string) => { + id: string + } // quickFiltersLogic + filterUpdated: (filter: QuickFilter) => { + filter: QuickFilter + } // quickFiltersLogic + loadQuickFiltersSuccess: ( + quickFilters: QuickFilter[], + payload?: any + ) => { + payload?: any + quickFilters: QuickFilter[] + } // quickFiltersLogic + clearQuickFilter: (filterId: string) => { + filterId: string + } + quickFiltersChanged: () => { + value: true + } + quickFiltersCommitted: () => { + value: true + } + quickFiltersUrlRestoreComplete: () => { + value: true + } + restoreClearQuickFilter: (filterId: string) => { + filterId: string + } + restoreFiltersFromUrl: () => {} + restoreQuickFilterValue: ( + filterId: string, + propertyName: string, + option: QuickFilterOption + ) => { + filterId: string + option: QuickFilterOption + propertyName: string + } + setQuickFilterValue: ( + filterId: string, + propertyName: string, + option: QuickFilterOption + ) => { + filterId: string + option: QuickFilterOption + propertyName: string + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface quickFiltersSectionLogicMeta { + key: string +} + +export type quickFiltersSectionLogicType = MakeLogicType< + quickFiltersSectionLogicValues, + quickFiltersSectionLogicActions, + QuickFiltersSectionLogicProps, + quickFiltersSectionLogicMeta +> + export const quickFiltersSectionLogic = kea([ path(['lib', 'components', 'QuickFilters', 'quickFiltersSectionLogic']), props({} as QuickFiltersSectionLogicProps), diff --git a/frontend/src/lib/components/Resizer/resizerLogic.ts b/frontend/src/lib/components/Resizer/resizerLogic.ts index a68b6cd0d660..b6118f3440ae 100644 --- a/frontend/src/lib/components/Resizer/resizerLogic.ts +++ b/frontend/src/lib/components/Resizer/resizerLogic.ts @@ -1,8 +1,6 @@ -import { actions, beforeUnmount, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, beforeUnmount, kea, key, listeners, path, props, reducers, selectors } from 'kea' import posthog from 'posthog-js' -import type { resizerLogicType } from './resizerLogicType' - export type ResizerEvent = { desiredSize: number } @@ -21,6 +19,52 @@ export type ResizerLogicProps = { onDoubleClick?: () => void } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface resizerLogicValues { + desiredSize: number | null + isResizeInProgress: boolean + isStart: boolean + isVertical: boolean + resizingSize: number | null + size: number | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface resizerLogicActions { + beginResize: (startXOrY: number) => { + startXOrY: number + } + endResize: () => { + value: true + } + resetDesiredSize: () => { + value: true + } + setDesiredSize: (size: number | null) => { + size: number | null + } + setResizingSize: (size: number | null) => { + size: number | null + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface resizerLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + desiredSize: (size: number | null, resizingSize: number | null, isResizeInProgress: boolean) => number | null + isVertical: (placement: 'bottom' | 'left' | 'right' | 'top') => boolean + isStart: (placement: 'bottom' | 'left' | 'right' | 'top') => boolean + } +} + +export type resizerLogicType = MakeLogicType< + resizerLogicValues, + resizerLogicActions, + ResizerLogicProps, + resizerLogicMeta +> + export const resizerLogic = kea([ props({} as ResizerLogicProps), key((props) => props.logicKey), @@ -61,12 +105,18 @@ export const resizerLogic = kea([ selectors({ desiredSize: [ (s) => [s.size, s.resizingSize, s.isResizeInProgress], - (size, resizingSize, isResizeInProgress) => { + (size: number | null, resizingSize: number | null, isResizeInProgress: boolean) => { return isResizeInProgress ? (resizingSize ?? size) : size }, ], - isVertical: [(_, p) => [p.placement], (placement) => ['left', 'right'].includes(placement)], - isStart: [(_, p) => [p.placement], (placement) => ['left', 'top'].includes(placement)], + isVertical: [ + (_, p) => [p.placement], + (placement: 'bottom' | 'left' | 'right' | 'top') => ['left', 'right'].includes(placement), + ], + isStart: [ + (_, p) => [p.placement], + (placement: 'bottom' | 'left' | 'right' | 'top') => ['left', 'top'].includes(placement), + ], }), listeners(({ cache, props, actions, values }) => ({ beginResize: ({ startXOrY }) => { diff --git a/frontend/src/lib/components/ReverseProxyChecker/reverseProxyCheckerLogic.ts b/frontend/src/lib/components/ReverseProxyChecker/reverseProxyCheckerLogic.ts index 44818de1ae8d..6b41c848b32a 100644 --- a/frontend/src/lib/components/ReverseProxyChecker/reverseProxyCheckerLogic.ts +++ b/frontend/src/lib/components/ReverseProxyChecker/reverseProxyCheckerLogic.ts @@ -1,4 +1,4 @@ -import { afterMount, kea, listeners, path } from 'kea' +import { MakeLogicType, afterMount, kea, listeners, path } from 'kea' import { loaders } from 'kea-loaders' import posthog from 'posthog-js' @@ -8,10 +8,38 @@ import { sceneLogic } from 'scenes/sceneLogic' import { hogql } from '~/queries/utils' -import type { reverseProxyCheckerLogicType } from './reverseProxyCheckerLogicType' - const CHECK_INTERVAL_MS = 1000 * 60 * 10 // 10 minutes +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface reverseProxyCheckerLogicValues { + hasReverseProxy: boolean | null + hasReverseProxyLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface reverseProxyCheckerLogicActions { + loadHasReverseProxy: () => any + loadHasReverseProxyFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadHasReverseProxySuccess: ( + hasReverseProxy: boolean | null, + payload?: any + ) => { + hasReverseProxy: boolean | null + payload?: any + } +} + +export type reverseProxyCheckerLogicType = MakeLogicType< + reverseProxyCheckerLogicValues, + reverseProxyCheckerLogicActions +> + export const reverseProxyCheckerLogic = kea([ path(['components', 'ReverseProxyChecker', 'reverseProxyCheckerLogic']), loaders(({ values, cache }) => ({ diff --git a/frontend/src/lib/components/RichContentEditor/richContentEditorLogic.ts b/frontend/src/lib/components/RichContentEditor/richContentEditorLogic.ts index df5909e3b502..2ea34cb94f33 100644 --- a/frontend/src/lib/components/RichContentEditor/richContentEditorLogic.ts +++ b/frontend/src/lib/components/RichContentEditor/richContentEditorLogic.ts @@ -1,6 +1,5 @@ -import { kea, key, path, props, selectors } from 'kea' +import { MakeLogicType, kea, key, path, props, selectors } from 'kea' -import type { richContentEditorLogicType } from './richContentEditorLogicType' import { RichContentEditorType, TTEditor } from './types' import { createEditor } from './utils' @@ -9,12 +8,34 @@ export interface RichContentEditorLogicProps { editor: TTEditor } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface richContentEditorLogicValues { + richContentEditor: RichContentEditorType + ttEditor: TTEditor +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface richContentEditorLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + ttEditor: (editor: TTEditor) => TTEditor + richContentEditor: (ttEditor: TTEditor) => RichContentEditorType + } +} + +export type richContentEditorLogicType = MakeLogicType< + richContentEditorLogicValues, + {}, + RichContentEditorLogicProps, + richContentEditorLogicMeta +> + export const richContentEditorLogic = kea([ path(['lib', 'components', 'RichContentEditor', 'richContentEditorLogic']), props({} as RichContentEditorLogicProps), key(({ logicKey }) => `RichContentEditor.${logicKey}`), selectors({ - ttEditor: [(_, p) => [p.editor], (editor): TTEditor => editor], - richContentEditor: [(s) => [s.ttEditor], (ttEditor): RichContentEditorType => createEditor(ttEditor)], + ttEditor: [(_, p) => [p.editor], (editor: TTEditor): TTEditor => editor], + richContentEditor: [(s) => [s.ttEditor], (ttEditor: TTEditor): RichContentEditorType => createEditor(ttEditor)], }), ]) diff --git a/frontend/src/lib/components/SaveToCohortModalContent/saveToCohortModalContentLogic.ts b/frontend/src/lib/components/SaveToCohortModalContent/saveToCohortModalContentLogic.ts index 515dc9c407e5..a0f86aef90ed 100644 --- a/frontend/src/lib/components/SaveToCohortModalContent/saveToCohortModalContentLogic.ts +++ b/frontend/src/lib/components/SaveToCohortModalContent/saveToCohortModalContentLogic.ts @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, listeners, path, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { router } from 'kea-router' @@ -13,8 +13,6 @@ import { urls } from 'scenes/urls' import { ActorsQuery } from '~/queries/schema/schema-general' import { CohortType } from '~/types' -import type { saveToCohortModalContentLogicType } from './saveToCohortModalContentLogicType' - const COHORTS_PER_PAGE = 100 export interface CohortFilters { @@ -29,6 +27,80 @@ const DEFAULT_COHORT_FILTERS: CohortFilters = { type: 'static', } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface saveToCohortModalContentLogicValues { + currentProjectId: number | null // projectLogic + cohortFilters: CohortFilters + cohorts: CountedPaginatedResponse + cohortsLoading: boolean + count: number + pagination: PaginationManual + paramsFromFilters: { + limit: number + offset: number + page?: number | undefined + search?: string | undefined + type: 'dynamic' | 'static' + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface saveToCohortModalContentLogicActions { + loadCohorts: () => any + loadCohortsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadCohortsSuccess: ( + cohorts: { + count: number + results: CohortType[] + }, + payload?: any + ) => { + cohorts: { + count: number + results: CohortType[] + } + payload?: any + } + saveQueryToCohort: ( + cohort: CohortType, + query: ActorsQuery + ) => { + cohort: CohortType + query: ActorsQuery + } + setCohortFilters: (filters: Partial) => { + filters: Partial + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface saveToCohortModalContentLogicMeta { + __keaTypeGenInternalSelectorTypes: { + count: (cohorts: CountedPaginatedResponse) => number + paramsFromFilters: (cohortFilters: CohortFilters) => { + limit: number + offset: number + page?: number | undefined + search?: string | undefined + type: 'dynamic' | 'static' + } + pagination: (cohortFilters: CohortFilters, count: number) => PaginationManual + } +} + +export type saveToCohortModalContentLogicType = MakeLogicType< + saveToCohortModalContentLogicValues, + saveToCohortModalContentLogicActions, + Record, + saveToCohortModalContentLogicMeta +> + export const saveToCohortModalContentLogic = kea([ path(['lib', 'components', 'SaveToCohortModal', 'saveToCohortModalContentLogic']), connect(() => ({ @@ -64,7 +136,7 @@ export const saveToCohortModalContentLogic = kea ({ - count: [(selectors) => [selectors.cohorts], (cohorts) => cohorts.count], + count: [(selectors) => [selectors.cohorts], (cohorts: CountedPaginatedResponse) => cohorts.count], paramsFromFilters: [ (s) => [s.cohortFilters], (filters: CohortFilters) => ({ @@ -75,7 +147,7 @@ export const saveToCohortModalContentLogic = kea [s.cohortFilters, s.count], - (filters, count): PaginationManual => { + (filters: CohortFilters, count: number): PaginationManual => { return { controlled: true, pageSize: COHORTS_PER_PAGE, diff --git a/frontend/src/lib/components/SceneDashboardChoice/sceneDashboardChoiceModalLogic.ts b/frontend/src/lib/components/SceneDashboardChoice/sceneDashboardChoiceModalLogic.ts index 49d24cafa423..63f8f19e6f2f 100644 --- a/frontend/src/lib/components/SceneDashboardChoice/sceneDashboardChoiceModalLogic.ts +++ b/frontend/src/lib/components/SceneDashboardChoice/sceneDashboardChoiceModalLogic.ts @@ -1,4 +1,4 @@ -import { actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import posthog from 'posthog-js' import { eventUsageLogic } from 'lib/utils/eventUsageLogic' @@ -10,7 +10,8 @@ import { userLogic } from 'scenes/userLogic' import { dashboardsModel } from '~/models/dashboardsModel' import { DashboardBasicType } from '~/types' -import type { sceneDashboardChoiceModalLogicType } from './sceneDashboardChoiceModalLogicType' +import type { Node } from '../../../queries/schema/schema-general' +import type { DashboardType, QueryBasedInsightModel, TeamPublicType, TeamType, UserType } from '../../../types' export type DashboardCompatibleScenes = Scene.ProjectHomepage | Scene.Person | Scene.Group @@ -24,6 +25,59 @@ export const sceneDescription: Record = { [Scene.ProjectHomepage]: 'this project', } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sceneDashboardChoiceModalLogicValues { + nameSortedDashboards: (DashboardBasicType | DashboardType>>>)[] // dashboardsModel + currentTeam: TeamPublicType | TeamType | null // teamLogic + user: UserType | null // userLogic + currentDashboardId: number | null + dashboards: (DashboardBasicType | DashboardType>>>)[] + isOpen: boolean + searchTerm: string | null +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sceneDashboardChoiceModalLogicActions { + updateCurrentTeam: (payload: Partial) => Partial // teamLogic + setUserScenePersonalisation: ( + scene: DashboardCompatibleScenes, + dashboard: number + ) => { + dashboard: number + scene: DashboardCompatibleScenes + } // userLogic + closeSceneDashboardChoiceModal: () => boolean + setSceneDashboardChoice: (dashboardId: number | null) => { + dashboardId: number | null + } + setSearchTerm: (searchTerm: string) => { + searchTerm: string + } + showSceneDashboardChoiceModal: () => boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sceneDashboardChoiceModalLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + currentDashboardId: (currentTeam: TeamPublicType | TeamType | null, user: UserType | null) => number | null + dashboards: ( + searchTerm: string | null, + nameSortedDashboards: ( + | DashboardBasicType + | DashboardType>>> + )[] + ) => (DashboardBasicType | DashboardType>>>)[] + } +} + +export type sceneDashboardChoiceModalLogicType = MakeLogicType< + sceneDashboardChoiceModalLogicValues, + sceneDashboardChoiceModalLogicActions, + SceneDashboardChoiceModalProps, + sceneDashboardChoiceModalLogicMeta +> + export const sceneDashboardChoiceModalLogic = kea([ path((key) => ['lib', 'components', 'SceneDashboardChoice', 'sceneDashboardChoiceModalLogic', key || 'unknown']), props({} as SceneDashboardChoiceModalProps), @@ -46,7 +100,10 @@ export const sceneDashboardChoiceModalLogic = kea ({ currentDashboardId: [ (s) => [s.currentTeam, s.user], - (currentTeam, user) => { + ( + currentTeam: null | import('~/types').TeamPublicType | import('~/types').TeamType, + user: null | import('~/types').UserType + ) => { let currentDashboard: number | DashboardBasicType | null = user?.scene_personalisation?.find((choice) => choice.scene === props.scene)?.dashboard ?? null @@ -59,7 +116,17 @@ export const sceneDashboardChoiceModalLogic = kea [s.searchTerm, s.nameSortedDashboards], - (searchTerm, dashboards) => { + ( + searchTerm: string | null, + dashboards: ( + | DashboardBasicType + | import('~/types').DashboardType< + import('~/types').QueryBasedInsightModel< + import('../../../queries/schema').Node> + > + > + )[] + ) => { dashboards = dashboards .filter((d) => !d.deleted) .sort((a, b) => (a.name ?? 'Untitled').localeCompare(b.name ?? 'Untitled')) diff --git a/frontend/src/lib/components/Search/searchLogic.tsx b/frontend/src/lib/components/Search/searchLogic.tsx index d619dc745dfb..e1d36c0e81cf 100644 --- a/frontend/src/lib/components/Search/searchLogic.tsx +++ b/frontend/src/lib/components/Search/searchLogic.tsx @@ -1,4 +1,4 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { loaders } from 'kea-loaders' import { IconBell, IconClock, IconDownload, IconLeave, IconNotification } from '@posthog/icons' @@ -25,7 +25,10 @@ import { matchesFlagDefinition } from '~/scenes/settings/flagGating' import { Setting, SettingSection, SettingSectionId } from '~/scenes/settings/types' import { ActivityTab, FileSystemIconColor, GroupTypeIndex, PersonType, SearchResponse } from '~/types' -import type { searchLogicType } from './searchLogicType' +import type { Noun } from '../../../models/groupsModel' +import type { FileSystemImport } from '../../../queries/schema/schema-general' +import type { GroupType, IntegrationType, UserType } from '../../../types' +import type { FeatureFlagsSet } from '../../logic/featureFlagLogic' import { filterSearchItems } from './utils' let cachedProductIconColorByType: Map | null = null @@ -157,6 +160,276 @@ export interface SettingsSectionSummary { }[] } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface searchLogicValues { + isCommandOpen: boolean // commandLogic + featureFlags: FeatureFlagsSet // featureFlagLogic + aggregationLabel: (groupTypeIndex: number | null | undefined, deferToUserWording?: boolean) => Noun // groupsModel + groupTypes: Map // groupsModel + organizationIntegrations: IntegrationType[] | null // organizationIntegrationsLogic + isDev: boolean | undefined // preflightLogic + cachedStarred: FileSystemEntry[] // projectTreeDataLogic + shortcutDataHasLoaded: boolean // projectTreeDataLogic + treeGroupItems: FileSystemImport[] // projectTreeDataLogic + cachedRecents: FileSystemEntry[] // recentItemsModel + recentsHasLoaded: boolean // recentItemsModel + sceneLogViewsByRef: Record // recentItemsModel + sceneLogViewsHasLoaded: boolean // recentItemsModel + user: UserType | null // userLogic + allCategories: SearchCategory[] + dataManagementItems: SearchItem[] + groupItems: SearchItem[] + groupSearchResults: Partial> + groupSearchResultsLoading: boolean + healthItems: SearchItem[] + isSearching: boolean + loadingStates: { + groupSearchResultsLoading: boolean + isToolsLoading: boolean + personSearchResultsLoading: boolean + playlistSearchResultsLoading: boolean + recentsHasLoaded: boolean + recentsLoading: boolean + starredHasLoaded: boolean + starredLoading: boolean + unifiedSearchResultsLoading: boolean + } + miscItems: SearchItem[] + newItems: SearchItem[] + peopleItems: SearchItem[] + personItems: SearchItem[] + personSearchResults: PersonType[] + personSearchResultsLoading: boolean + playlistItems: SearchItem[] + playlistSearchResults: FileSystemEntry[] + playlistSearchResultsLoading: boolean + recentItems: SearchItem[] + search: string + searchPending: boolean + searchedRecents: FileSystemEntry[] | null + searchedRecentsLoading: boolean + settingsItems: SearchItem[] + settingsSections: SettingsSectionSummary[] + starredItems: SearchItem[] + toolsItems: SearchItem[] + unifiedSearchItems: Record + unifiedSearchResults: SearchResponse | null + unifiedSearchResultsLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface searchLogicActions { + loadGroupSearchResults: ({ searchTerm }: { searchTerm: string }) => { + searchTerm: string + } + loadGroupSearchResultsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadGroupSearchResultsSuccess: ( + groupSearchResults: Partial>, + payload?: { + searchTerm: string + } + ) => { + groupSearchResults: Partial> + payload?: { + searchTerm: string + } + } + loadPersonSearchResults: ({ searchTerm }: { searchTerm: string }) => { + searchTerm: string + } + loadPersonSearchResultsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadPersonSearchResultsSuccess: ( + personSearchResults: PersonType[], + payload?: { + searchTerm: string + } + ) => { + personSearchResults: PersonType[] + payload?: { + searchTerm: string + } + } + loadPlaylistSearchResults: ({ searchTerm }: { searchTerm: string }) => { + searchTerm: string + } + loadPlaylistSearchResultsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadPlaylistSearchResultsSuccess: ( + playlistSearchResults: FileSystemEntry[], + payload?: { + searchTerm: string + } + ) => { + playlistSearchResults: FileSystemEntry[] + payload?: { + searchTerm: string + } + } + loadUnifiedSearchResults: ({ searchTerm }: { searchTerm: string }) => { + searchTerm: string + } + loadUnifiedSearchResultsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadUnifiedSearchResultsSuccess: ( + unifiedSearchResults: SearchResponse | null, + payload?: { + searchTerm: string + } + ) => { + unifiedSearchResults: SearchResponse | null + payload?: { + searchTerm: string + } + } + searchRecents: ({ search }: { search: string }) => { + search: string + } + searchRecentsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + searchRecentsSuccess: ( + searchedRecents: FileSystemEntry[] | null, + payload?: { + search: string + } + ) => { + searchedRecents: FileSystemEntry[] | null + payload?: { + search: string + } + } + setSearch: (search: string) => { + search: string + } + setSettingsSections: (sections: SettingsSectionSummary[]) => { + sections: SettingsSectionSummary[] + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface searchLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + isSearching: ( + searchedRecentsLoading: boolean, + unifiedSearchResultsLoading: boolean, + groupSearchResultsLoading: boolean, + personSearchResultsLoading: boolean, + playlistSearchResultsLoading: boolean, + searchPending: boolean, + search: string + ) => boolean + recentItems: ( + searchedRecents: FileSystemEntry[] | null, + cachedRecents: FileSystemEntry[], + search: string + ) => SearchItem[] + starredItems: (cachedStarred: FileSystemEntry[]) => SearchItem[] + toolsItems: ( + featureFlags: FeatureFlagsSet, + isDev: boolean | undefined, + user: UserType | null, + sceneLogViewsByRef: Record + ) => SearchItem[] + dataManagementItems: ( + featureFlags: FeatureFlagsSet, + isDev: boolean | undefined, + user: UserType | null, + sceneLogViewsByRef: Record + ) => SearchItem[] + newItems: (featureFlags: FeatureFlagsSet, isDev: boolean | undefined, user: UserType | null) => SearchItem[] + peopleItems: (treeGroupItems: FileSystemImport[], sceneLogViewsByRef: Record) => SearchItem[] + groupItems: ( + groupSearchResults: Partial>, + aggregationLabel: (groupTypeIndex: number | null | undefined, deferToUserWording?: boolean) => Noun + ) => SearchItem[] + personItems: (personSearchResults: PersonType[]) => SearchItem[] + playlistItems: (playlistSearchResults: FileSystemEntry[]) => SearchItem[] + healthItems: (sceneLogViewsByRef: Record) => SearchItem[] + miscItems: (sceneLogViewsByRef: Record) => SearchItem[] + settingsItems: ( + featureFlags: FeatureFlagsSet, + organizationIntegrations: IntegrationType[] | null, + settingsSections: SettingsSectionSummary[] + ) => SearchItem[] + unifiedSearchItems: (unifiedSearchResults: SearchResponse | null) => Record + loadingStates: ( + unifiedSearchResultsLoading: boolean, + recentsHasLoaded: boolean, + shortcutDataHasLoaded: boolean, + sceneLogViewsHasLoaded: boolean, + personSearchResultsLoading: boolean, + groupSearchResultsLoading: boolean, + playlistSearchResultsLoading: boolean + ) => { + groupSearchResultsLoading: boolean + isToolsLoading: boolean + personSearchResultsLoading: boolean + playlistSearchResultsLoading: boolean + recentsHasLoaded: boolean + recentsLoading: boolean + starredHasLoaded: boolean + starredLoading: boolean + unifiedSearchResultsLoading: boolean + } + allCategories: ( + recentItems: SearchItem[], + starredItems: SearchItem[], + toolsItems: SearchItem[], + dataManagementItems: SearchItem[], + peopleItems: SearchItem[], + healthItems: SearchItem[], + miscItems: SearchItem[], + settingsItems: SearchItem[], + newItems: SearchItem[], + personItems: SearchItem[], + groupItems: SearchItem[], + playlistItems: SearchItem[], + unifiedSearchItems: Record, + loadingStates: { + groupSearchResultsLoading: boolean + isToolsLoading: boolean + personSearchResultsLoading: boolean + playlistSearchResultsLoading: boolean + recentsHasLoaded: boolean + recentsLoading: boolean + starredHasLoaded: boolean + starredLoading: boolean + unifiedSearchResultsLoading: boolean + }, + search: string + ) => SearchCategory[] + } +} + +export type searchLogicType = MakeLogicType + export const searchLogic = kea([ path((logicKey) => ['lib', 'components', 'Search', 'searchLogic', logicKey]), props({} as SearchLogicProps), @@ -355,14 +628,18 @@ export const searchLogic = kea([ ], recentItems: [ (s) => [s.searchedRecents, s.cachedRecents, s.search], - (searchedRecents, cachedRecents, search): SearchItem[] => { + ( + searchedRecents: FileSystemEntry[] | null, + cachedRecents: FileSystemEntry[], + search: string + ): SearchItem[] => { const source = search.trim() ? (searchedRecents ?? []) : cachedRecents.slice(0, RECENTS_LIMIT) return source.map((item) => fileSystemEntryToSearchItem(item, { id: item.path, category: 'recents' })) }, ], starredItems: [ (s) => [s.cachedStarred], - (cachedStarred): SearchItem[] => { + (cachedStarred: FileSystemEntry[]): SearchItem[] => { return cachedStarred .filter((e) => e.type !== 'folder') .slice(0, STARRED_LIMIT) @@ -377,7 +654,12 @@ export const searchLogic = kea([ ], toolsItems: [ (s) => [s.featureFlags, s.isDev, s.user, s.sceneLogViewsByRef], - (featureFlags, isDev, user, sceneLogViewsByRef): SearchItem[] => { + ( + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + isDev: boolean | undefined, + user: null | import('~/types').UserType, + sceneLogViewsByRef: Record + ): SearchItem[] => { const allProducts = getTreeItemsProducts() const filteredProducts = allProducts.filter((product) => { if (!product.href) { @@ -444,7 +726,12 @@ export const searchLogic = kea([ ], dataManagementItems: [ (s) => [s.featureFlags, s.isDev, s.user, s.sceneLogViewsByRef], - (featureFlags, isDev, user, sceneLogViewsByRef): SearchItem[] => { + ( + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + isDev: boolean | undefined, + user: null | import('~/types').UserType, + sceneLogViewsByRef: Record + ): SearchItem[] => { const allMetadata = getTreeItemsMetadata() const filteredMetadata = allMetadata.filter((item) => { if (!isDev && !user?.is_staff && item.category === 'Unreleased') { @@ -496,7 +783,11 @@ export const searchLogic = kea([ ], newItems: [ (s) => [s.featureFlags, s.isDev, s.user], - (featureFlags, isDev, user): SearchItem[] => { + ( + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + isDev: boolean | undefined, + user: null | import('~/types').UserType + ): SearchItem[] => { const allNewItems = getTreeItemsNew() const filteredItems = allNewItems.filter((item) => { if (!isDev && !user?.is_staff && item.category === 'Unreleased') { @@ -545,7 +836,10 @@ export const searchLogic = kea([ ], peopleItems: [ (s) => [s.treeGroupItems, s.sceneLogViewsByRef], - (treeGroupItems, sceneLogViewsByRef): SearchItem[] => { + ( + treeGroupItems: import('~/queries/schema/schema-general').FileSystemImport[], + sceneLogViewsByRef: Record + ): SearchItem[] => { const combined = [...getDefaultTreePersons(), ...treeGroupItems] return combined.map((item) => ({ id: `people-${item.path}`, @@ -567,7 +861,13 @@ export const searchLogic = kea([ ], groupItems: [ (s) => [s.groupSearchResults, s.aggregationLabel], - (groupSearchResults, aggregationLabel): SearchItem[] => { + ( + groupSearchResults: Partial>, + aggregationLabel: ( + groupTypeIndex: number | null | undefined, + deferToUserWording?: boolean + ) => import('~/models/groupsModel').Noun + ): SearchItem[] => { const items: SearchItem[] = [] for (const [groupTypeIndexString, groups] of Object.entries(groupSearchResults)) { const groupTypeIndex = parseInt(groupTypeIndexString, 10) as GroupTypeIndex @@ -596,7 +896,7 @@ export const searchLogic = kea([ ], personItems: [ (s) => [s.personSearchResults], - (personSearchResults): SearchItem[] => { + (personSearchResults: PersonType[]): SearchItem[] => { return personSearchResults .filter((person) => person.uuid) // Skip persons without uuid to avoid invalid URLs .map((person) => { @@ -624,7 +924,7 @@ export const searchLogic = kea([ ], playlistItems: [ (s) => [s.playlistSearchResults], - (playlistSearchResults): SearchItem[] => { + (playlistSearchResults: FileSystemEntry[]): SearchItem[] => { return playlistSearchResults.map((item) => { const name = splitPath(item.path).pop() return { @@ -641,7 +941,7 @@ export const searchLogic = kea([ ], healthItems: [ (s) => [s.sceneLogViewsByRef], - (sceneLogViewsByRef): SearchItem[] => [ + (sceneLogViewsByRef: Record): SearchItem[] => [ { id: 'health-pipeline-status', name: 'Pipeline status', @@ -666,7 +966,7 @@ export const searchLogic = kea([ ], miscItems: [ (s) => [s.sceneLogViewsByRef], - (sceneLogViewsByRef): SearchItem[] => [ + (sceneLogViewsByRef: Record): SearchItem[] => [ { id: 'misc-exports', name: 'Exports', @@ -715,7 +1015,11 @@ export const searchLogic = kea([ ], settingsItems: [ (s) => [s.featureFlags, s.organizationIntegrations, s.settingsSections], - (featureFlags, organizationIntegrations, settingsSections): SearchItem[] => { + ( + featureFlags: import('lib/logic/featureFlagLogic').FeatureFlagsSet, + organizationIntegrations: import('~/types').IntegrationType[] | null, + settingsSections: SettingsSectionSummary[] + ): SearchItem[] => { const checkFlag = (flagKey: Pick['flag']): boolean => matchesFlagDefinition(flagKey, featureFlags) @@ -798,7 +1102,7 @@ export const searchLogic = kea([ ], unifiedSearchItems: [ (s) => [s.unifiedSearchResults], - (unifiedSearchResults): Record => { + (unifiedSearchResults: SearchResponse | null): Record => { if (!unifiedSearchResults) { return {} } diff --git a/frontend/src/lib/components/Sharing/sharePasswordsLogic.ts b/frontend/src/lib/components/Sharing/sharePasswordsLogic.ts index 5d7a7d2030b7..5d0fe6d8d83b 100644 --- a/frontend/src/lib/components/Sharing/sharePasswordsLogic.ts +++ b/frontend/src/lib/components/Sharing/sharePasswordsLogic.ts @@ -1,4 +1,4 @@ -import { actions, kea, key, listeners, path, props, reducers } from 'kea' +import { MakeLogicType, actions, kea, key, listeners, path, props, reducers } from 'kea' import { loaders } from 'kea-loaders' import api from 'lib/api' @@ -6,8 +6,6 @@ import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast' import { SharePasswordType } from '~/types' -import type { sharePasswordsLogicType } from './sharePasswordsLogicType' - export interface SharePasswordsLogicProps { dashboardId?: number insightId?: number @@ -15,6 +13,83 @@ export interface SharePasswordsLogicProps { notebookShortId?: string } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sharePasswordsLogicValues { + createdPasswordResult: { + created_at: string + created_by_email: string + id: string + note: string + password: string + } | null + isCreatingPassword: boolean + newPasswordModalOpen: boolean + sharePasswords: SharePasswordType[] + sharePasswordsLoading: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sharePasswordsLogicActions { + clearCreatedPasswordResult: () => { + value: true + } + createPassword: ( + password?: string, + note?: string + ) => { + note: string | undefined + password: string | undefined + } + createPasswordFailure: (error: any) => { + error: any + } + createPasswordSuccess: (response: any) => { + response: any + } + deletePassword: (passwordId: string) => { + passwordId: string + } + loadSharePasswords: () => { + value: true + } + loadSharePasswordsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadSharePasswordsSuccess: ( + sharePasswords: SharePasswordType[], + payload?: { + value: true + } + ) => { + sharePasswords: SharePasswordType[] + payload?: { + value: true + } + } + setNewPasswordModalOpen: (open: boolean) => { + open: boolean + } + setSharePasswords: (passwords: SharePasswordType[]) => { + passwords: SharePasswordType[] + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sharePasswordsLogicMeta { + key: string +} + +export type sharePasswordsLogicType = MakeLogicType< + sharePasswordsLogicValues, + sharePasswordsLogicActions, + SharePasswordsLogicProps, + sharePasswordsLogicMeta +> + export const sharePasswordsLogic = kea([ path(['lib', 'components', 'Sharing', 'sharePasswordsLogic']), props({} as SharePasswordsLogicProps), diff --git a/frontend/src/lib/components/Sharing/sharingLogic.ts b/frontend/src/lib/components/Sharing/sharingLogic.ts index c13bcab25b56..571b8d4e42be 100644 --- a/frontend/src/lib/components/Sharing/sharingLogic.ts +++ b/frontend/src/lib/components/Sharing/sharingLogic.ts @@ -1,5 +1,6 @@ -import { actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' +import { MakeLogicType, actions, afterMount, connect, kea, key, listeners, path, props, reducers, selectors } from 'kea' import { forms } from 'kea-forms' +import type { DeepPartial, DeepPartialMap, FieldName, ValidationErrorType } from 'kea-forms' import { loaders } from 'kea-loaders' import api from 'lib/api' @@ -13,8 +14,6 @@ import { userLogic } from 'scenes/userLogic' import { dashboardsModel } from '~/models/dashboardsModel' import { AvailableFeature, InsightShortId, OrganizationType, SharingConfigurationType } from '~/types' -import type { sharingLogicType } from './sharingLogicType' - export interface SharingLogicProps { dashboardId?: number insightShortId?: InsightShortId @@ -60,6 +59,287 @@ const propsToApiParams = async ( } } +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sharingLogicValues { + accessControlAvailable: boolean + embedCode: string + embedLink: string + iframeKey: number + iframeProperties: { + allowFullScreen: true + frameBorder: number + height: string + key: number + sandbox: string + src: string + width: string + } + isSharingSettingsSubmitting: boolean + isSharingSettingsValid: boolean + params: any + shareLink: string + sharingAllowed: boolean + sharingConfiguration: SharingConfigurationType | null + sharingConfigurationLoading: boolean + sharingSettings: { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + } + sharingSettingsAllErrors: Record + sharingSettingsChanged: boolean + sharingSettingsErrors: DeepPartialMap< + { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + }, + ValidationErrorType + > + sharingSettingsHasErrors: boolean + sharingSettingsManualErrors: Record + sharingSettingsTouched: boolean + sharingSettingsTouches: Record + sharingSettingsValidationErrors: DeepPartialMap< + { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + }, + ValidationErrorType + > + showPreview: boolean + showSharingSettingsErrors: boolean + siteUrl: string | undefined + whitelabelAvailable: boolean +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sharingLogicActions { + loadSharingConfiguration: () => any + loadSharingConfigurationFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + loadSharingConfigurationSuccess: ( + sharingConfiguration: SharingConfigurationType | null, + payload?: any + ) => { + sharingConfiguration: SharingConfigurationType | null + payload?: any + } + reloadIframe: () => { + value: true + } + resetSharingSettings: (values?: { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + }) => { + values?: { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + } + } + setIsEnabled: (enabled: boolean) => boolean + setIsEnabledFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + setIsEnabledSuccess: ( + sharingConfiguration: SharingConfigurationType | null, + payload?: boolean + ) => { + sharingConfiguration: SharingConfigurationType | null + payload?: boolean + } + setPasswordRequired: (password_required: boolean) => boolean + setPasswordRequiredFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + setPasswordRequiredSuccess: ( + sharingConfiguration: SharingConfigurationType | null, + payload?: boolean + ) => { + sharingConfiguration: SharingConfigurationType | null + payload?: boolean + } + setSharingSettingsManualErrors: (errors: Record) => { + errors: Record + } + setSharingSettingsValue: ( + key: FieldName, + value: any + ) => { + name: FieldName + value: any + } + setSharingSettingsValues: ( + values: DeepPartial<{ + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + }> + ) => { + values: DeepPartial<{ + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + }> + } + submitSharingSettings: () => { + value: boolean + } + submitSharingSettingsFailure: ( + error: Error, + errors: Record + ) => { + error: Error + errors: Record + } + submitSharingSettingsRequest: (sharingSettings: { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + }) => { + sharingSettings: { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + } + } + submitSharingSettingsSuccess: (sharingSettings: { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + }) => { + sharingSettings: { + hideExtraDetails: boolean + legend: boolean + noHeader: boolean + showInspector: boolean + theme: string + whitelabel: boolean + } + } + togglePreview: () => { + value: true + } + touchSharingSettingsField: (key: string) => { + key: string + } + updateSettings: (settings: Record) => Record + updateSettingsFailure: ( + error: string, + errorObject?: any + ) => { + error: string + errorObject?: any + } + updateSettingsSuccess: ( + sharingConfiguration: SharingConfigurationType | null, + payload?: Record + ) => { + sharingConfiguration: SharingConfigurationType | null + payload?: Record + } +} + +// Generated by kea-typegen. Update if you're an agent, ignore if you're human. +export interface sharingLogicMeta { + key: string + __keaTypeGenInternalSelectorTypes: { + siteUrl: (preflight: null | import('~/types').PreflightStatus) => string | undefined + whitelabelAvailable: ( + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean + ) => boolean + accessControlAvailable: ( + hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean + ) => boolean + sharingAllowed: (currentOrganization: OrganizationType | null) => boolean + params: (arg: any) => any + shareLink: ( + siteUrl: string | undefined, + sharingConfiguration: SharingConfigurationType | null, + params: any + ) => string + embedLink: ( + siteUrl: string | undefined, + sharingConfiguration: SharingConfigurationType | null, + params: any + ) => string + iframeProperties: ( + embedLink: string, + iframeKey: number + ) => { + allowFullScreen: true + frameBorder: number + height: string + key: number + sandbox: string + src: string + width: string + } + embedCode: (iframeProperties: { + allowFullScreen: true + frameBorder: number + height: string + key: number + sandbox: string + src: string + width: string + }) => string + } +} + +export type sharingLogicType = MakeLogicType< + sharingLogicValues, + sharingLogicActions, + SharingLogicProps, + sharingLogicMeta +> + export const sharingLogic = kea([ path(['lib', 'components', 'Sharing', 'sharingLogic']), props({} as SharingLogicProps), @@ -152,15 +432,20 @@ export const sharingLogic = kea([ }, }), selectors({ - siteUrl: [() => [preflightLogic.selectors.preflight], (preflight) => preflight?.site_url], + siteUrl: [ + () => [preflightLogic.selectors.preflight], + (preflight: null | import('~/types').PreflightStatus) => preflight?.site_url, + ], whitelabelAvailable: [ () => [userLogic.selectors.hasAvailableFeature], - (hasAvailableFeature) => hasAvailableFeature(AvailableFeature.WHITE_LABELLING), + (hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean) => + hasAvailableFeature(AvailableFeature.WHITE_LABELLING), ], accessControlAvailable: [ () => [userLogic.selectors.hasAvailableFeature], - (hasAvailableFeature) => hasAvailableFeature(AvailableFeature.ACCESS_CONTROL), + (hasAvailableFeature: (feature: AvailableFeature, currentUsage?: number | undefined) => boolean) => + hasAvailableFeature(AvailableFeature.ACCESS_CONTROL), ], sharingAllowed: [ @@ -177,19 +462,19 @@ export const sharingLogic = kea([ shareLink: [ (s) => [s.siteUrl, s.sharingConfiguration, s.params], - (siteUrl, sharingConfiguration, params) => + (siteUrl: string | undefined, sharingConfiguration: SharingConfigurationType | null, params) => sharingConfiguration ? siteUrl + urls.shared(sharingConfiguration.access_token, params) : '', ], embedLink: [ (s) => [s.siteUrl, s.sharingConfiguration, s.params], - (siteUrl, sharingConfiguration, params) => + (siteUrl: string | undefined, sharingConfiguration: SharingConfigurationType | null, params) => sharingConfiguration ? siteUrl + urls.embedded(sharingConfiguration.access_token, params) : '', ], iframeProperties: [ (s) => [s.embedLink, s.iframeKey], - (embedLink, iframeKey) => ({ + (embedLink: string, iframeKey: number) => ({ width: defaultIframeConfig.width, height: defaultIframeConfig.height, frameBorder: 0, @@ -203,7 +488,15 @@ export const sharingLogic = kea([ embedCode: [ (s) => [s.iframeProperties], - (iframeProperties) => + (iframeProperties: { + allowFullScreen: true + frameBorder: number + height: string + key: number + sandbox: string + src: string + width: string + }) => `