diff --git a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx index 371e8c3a12524..e29c933aac59f 100644 --- a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx +++ b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx @@ -1,5 +1,4 @@ import { - IconApps, IconCalculator, IconChat, IconCheck, @@ -7,6 +6,7 @@ import { IconDashboard, IconDatabase, IconDay, + IconDecisionTree, IconExternal, IconEye, IconFunnels, @@ -617,7 +617,7 @@ export const commandPaletteLogic = kea([ }, }, { - icon: IconApps, + icon: IconDecisionTree, display: 'Go to Apps', synonyms: ['integrations'], executor: () => { diff --git a/frontend/src/lib/lemon-ui/icons/categories.ts b/frontend/src/lib/lemon-ui/icons/categories.ts new file mode 100644 index 0000000000000..f209c9f400900 --- /dev/null +++ b/frontend/src/lib/lemon-ui/icons/categories.ts @@ -0,0 +1,189 @@ +export const UNUSED_ICONS = [ + 'IconAdvanced', + 'IconAsterisk', + 'IconGridMasonry', + 'IconApps', + 'IconRibbon', + 'IconPulse', + 'IconPineapple', + 'IconPizza', + 'IconTarget', + 'IconThumbsUp', + 'IconThumbsUpFilled', + 'IconThumbsDown', + 'IconThumbsDownFilled', + 'IconShieldLock', +] + +export const OBJECTS = { + Misc: [ + 'IconPalette', + 'IconMegaphone', + 'IconRocket', + 'IconMap', + 'IconTie', + 'IconCoffee', + 'IconFlag', + 'IconCreditCard', + 'IconCrown', + 'IconBolt', + 'IconBook', + 'IconConfetti', + 'IconPresent', + 'IconMagicWand', + 'IconMagic', + 'IconHelmet', + 'IconSpotlight', + 'IconGraduationCap', + 'IconLightBulb', + 'IconBell', + 'IconBox', + 'IconBuilding', + 'IconEye', + 'IconFeatures', + 'IconHome', + 'IconHomeFilled', + 'IconGear', + 'IconGearFilled', + 'IconStack', + ], + People: ['IconPeople', 'IconPeopleFilled', 'IconPerson', 'IconProfile', 'IconUser'], + 'Business & Finance': ['IconStore', 'IconCart', 'IconReceipt', 'IconPiggyBank'], + Time: ['IconHourglass', 'IconCalendar', 'IconClock'], + Nature: ['IconDay', 'IconNight', 'IconGlobe', 'IconCloud', 'IconBug'], + Text: ['IconDocument', 'IconBrackets', 'IconTextWidth', 'IconQuote', 'IconLetter', 'IconNewspaper'], +} + +export const TECHNOLOGY = { + Messaging: ['IconSend', 'IconHeadset', 'IconMessage', 'IconNotification', 'IconChat', 'IconThoughtBubble'], + Hardware: [ + 'IconLaptop', + 'IconPhone', + 'IconWebcam', + 'IconMicrophone', + 'IconKeyboard', + 'IconServer', + 'IconDatabase', + 'IconHardDrive', + ], + Software: ['IconBrowser', 'IconCode', 'IconCodeInsert', 'IconTerminal', 'IconApp'], + UI: [ + 'IconPassword', + 'IconToggle', + 'IconLoading', + 'IconSpinner', + 'IconBrightness', + 'IconCursor', + 'IconCursorBox', + 'IconCursorClick', + 'IconToolbar', + 'IconToolbarFilled', + 'IconCheckbox', + 'IconList', + 'IconColumns', + ], +} + +export const ELEMENTS = { + Actions: [ + 'IconCopy', + 'IconTrash', + 'IconUndo', + 'IconRedo', + 'IconRevert', + 'IconSearch', + 'IconUpload', + 'IconShare', + 'IconDownload', + 'IconLeave', + 'IconPin', + 'IconPinFilled', + 'IconPencil', + 'IconOpenSidebar', + 'IconFilter', + 'IconArchive', + 'IconSort', + 'IconExternal', + ], + Symbols: [ + 'IconLock', + 'IconUnlock', + 'IconPrivacy', + 'IconShield', + 'IconWarning', + 'IconQuestion', + 'IconInfo', + 'IconCheckCircle', + 'IconCheck', + 'IconX', + 'IconEllipsis', + ], + 'Arrows & Shapes': [ + 'IconArrowLeft', + 'IconArrowRight', + 'IconArrowCircleLeft', + 'IconArrowCircleRight', + 'IconArrowRightDown', + 'IconArrowUpRight', + 'IconCollapse', + 'IconExpand', + 'IconCollapse45', + 'IconExpand45', + 'IconChevronDown', + 'IconTriangleDown', + 'IconTriangleDownFilled', + 'IconTriangleUp', + 'IconTriangleUpFilled', + 'IconStar', + 'IconStarFilled', + 'IconHeart', + 'IconHeartFilled', + ], + Mathematics: [ + 'IconPlus', + 'IconPlusSmall', + 'IconPlusSquare', + 'IconMinus', + 'IconMinusSmall', + 'IconMinusSquare', + 'IconMultiply', + 'IconPercentage', + 'IconCalculator', + ], +} + +export const TEAMS_AND_COMPANIES = { + Analytics: [ + 'IconCorrelationAnalysis', + 'IconGraph', + 'IconLineGraph', + 'IconRetention', + 'IconFunnels', + 'IconGanttChart', + 'IconTrending', + 'IconTrends', + 'IconLifecycle', + 'IconPieChart', + 'IconUserPaths', + 'IconStickiness', + 'IconPageChart', + 'IconSampling', + 'IconLive', + 'IconBadge', + ], + Replay: [ + 'IconPlay', + 'IconPlayFilled', + 'IconPlaylist', + 'IconPause', + 'IconPauseFilled', + 'IconRewind', + 'IconRecord', + 'IconRewindPlay', + 'IconVideoCamera', + ], + 'Feature Success': ['IconFlask', 'IconTestTube', 'IconMultivariateTesting', 'IconSplitTesting'], + Pipeline: ['IconWebhooks', 'IconDecisionTree'], + 'Product OS': ['IconNotebook', 'IconHogQL', 'IconDashboard', 'IconSupport'], + Logos: ['IconLogomark', 'IconGithub'], +} diff --git a/frontend/src/lib/lemon-ui/icons/icons.test.ts b/frontend/src/lib/lemon-ui/icons/icons.test.ts new file mode 100644 index 0000000000000..f3b888ca4ac80 --- /dev/null +++ b/frontend/src/lib/lemon-ui/icons/icons.test.ts @@ -0,0 +1,17 @@ +import * as packageIcons from '@posthog/icons' + +import { ELEMENTS, OBJECTS, TEAMS_AND_COMPANIES, TECHNOLOGY, UNUSED_ICONS } from './categories' + +describe('icons', () => { + it('ensures all icons are categorised', async () => { + const validPackageIcons = Object.keys(packageIcons).filter((i) => !['BaseIcon', 'default'].includes(i)) + const categories = { ...OBJECTS, ...TECHNOLOGY, ...ELEMENTS, ...TEAMS_AND_COMPANIES } + const categorisedIcons = Object.values(categories) + .map((category) => Object.values(category)) + .flat(2) + + const allIcons = [...categorisedIcons, ...UNUSED_ICONS] + + expect(validPackageIcons.filter((i) => !allIcons.includes(i))).toEqual([]) + }) +}) diff --git a/frontend/src/lib/lemon-ui/icons/icons3000.stories.tsx b/frontend/src/lib/lemon-ui/icons/icons3000.stories.tsx new file mode 100644 index 0000000000000..69af4d9765ef1 --- /dev/null +++ b/frontend/src/lib/lemon-ui/icons/icons3000.stories.tsx @@ -0,0 +1,92 @@ +import * as packageIcons from '@posthog/icons' +import { Meta, StoryObj } from '@storybook/react' +import { copyToClipboard } from 'lib/utils/copyToClipboard' + +import { LemonCollapse } from '../LemonCollapse' +import { Tooltip } from '../Tooltip' +import { ELEMENTS, OBJECTS, TEAMS_AND_COMPANIES, TECHNOLOGY } from './categories' + +const meta: Meta = { + title: 'PostHog 3000/Icons', + tags: ['test-skip'], + parameters: { + previewTabs: { + 'storybook/docs/panel': { + hidden: true, + }, + }, + }, +} +export default meta + +const posthogIcons = Object.entries(packageIcons) + .filter(([key]) => key !== 'BaseIcon') + .map(([key, Icon]) => ({ name: key, icon: Icon })) + +const IconTemplate = ({ icons }: { icons: { name: string; icon: any }[] }): JSX.Element => { + const onClick = (name: string): void => { + void copyToClipboard(name) + } + + return ( +
+ {icons.map(({ name, icon: Icon }) => { + return ( +
onClick(name)} key={name} className="flex justify-center"> + +
+ + {name} +
+
+
+ ) + })} +
+ ) +} + +export function Alphabetical(): JSX.Element { + return +} + +const GroupBase = ({ group }: { group: Record }): JSX.Element => { + return ( + { + return { + key, + header: key, + content: ( + { + return { name: icon, icon: packageIcons[icon] } + })} + /> + ), + } + })} + /> + ) +} + +export const Elements: StoryObj = (): JSX.Element => { + return +} +Elements.storyName = 'Category - Elements' + +export const TeamsAndCompanies: StoryObj = (): JSX.Element => { + return +} +TeamsAndCompanies.storyName = 'Category - Teams & Companies' + +export const Technology: StoryObj = (): JSX.Element => { + return +} +Technology.storyName = 'Category - Technology' + +export const Objects: StoryObj = (): JSX.Element => { + return +} +Objects.storyName = 'Category - Objects' diff --git a/frontend/src/toolbar/bar/Toolbar.tsx b/frontend/src/toolbar/bar/Toolbar.tsx index 3bdda9e523e79..f255ccc26800d 100644 --- a/frontend/src/toolbar/bar/Toolbar.tsx +++ b/frontend/src/toolbar/bar/Toolbar.tsx @@ -7,7 +7,7 @@ import { IconLogomark, IconNight, IconQuestion, - IconTarget, + IconSearch, IconToggle, IconX, } from '@posthog/icons' @@ -185,7 +185,7 @@ export function Toolbar(): JSX.Element { /> {isAuthenticated ? ( <> - } menuId="inspect" /> + } menuId="inspect" /> } menuId="heatmap" /> } menuId="actions" /> } menuId="flags" title="Feature flags" /> diff --git a/package.json b/package.json index f422e9835a6e9..0a268fc208fd5 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "@medv/finder": "^3.1.0", "@microlink/react-json-view": "^1.21.3", "@monaco-editor/react": "4.4.6", - "@posthog/icons": "0.6.3", + "@posthog/icons": "0.6.7", "@posthog/plugin-scaffold": "^1.4.4", "@react-hook/size": "^2.1.2", "@rrweb/types": "2.0.0-alpha.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca7351e1a360f..ef81ba7d4c4d9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -47,8 +47,8 @@ dependencies: specifier: 4.4.6 version: 4.4.6(monaco-editor@0.39.0)(react-dom@18.2.0)(react@18.2.0) '@posthog/icons': - specifier: 0.6.3 - version: 0.6.3(react-dom@18.2.0)(react@18.2.0) + specifier: 0.6.7 + version: 0.6.7(react-dom@18.2.0)(react@18.2.0) '@posthog/plugin-scaffold': specifier: ^1.4.4 version: 1.4.4 @@ -5180,8 +5180,8 @@ packages: resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} dev: false - /@posthog/icons@0.6.3(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-EQ86OFe9omsU9vUCvISksNN+QPH/VHiE4Z0A8FZApSKbiCtsX2zecPgX3ou765V284ktajkeROsrUI0luj8jRw==} + /@posthog/icons@0.6.7(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Jxizmu+fIW6y3kl13oC3avq9YtfRfszmtme75kYFnm+btRGOjwgnTGYPsPCAz9Pw5LsTqii/uNngUsMNotiTZA==} peerDependencies: react: '>=16.14.0' react-dom: '>=16.14.0' diff --git a/posthog/api/authentication.py b/posthog/api/authentication.py index 9b7dc954a97fa..10538c1d77ceb 100644 --- a/posthog/api/authentication.py +++ b/posthog/api/authentication.py @@ -179,6 +179,10 @@ def create(self, request: Request, *args: Any, **kwargs: Any) -> Response: """ response = super().create(request, *args, **kwargs) response.status_code = getattr(self, "SUCCESS_STATUS_CODE", status.HTTP_200_OK) + + if response.status_code == status.HTTP_204_NO_CONTENT: + response.data = None + return response diff --git a/posthog/api/test/test_authentication.py b/posthog/api/test/test_authentication.py index a33a59dd0549b..ef83517c918c7 100644 --- a/posthog/api/test/test_authentication.py +++ b/posthog/api/test/test_authentication.py @@ -317,6 +317,7 @@ def test_anonymous_user_can_request_password_reset(self, mock_capture): response = self.client.post("/api/reset/", {"email": self.CONFIG_EMAIL}) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT) self.assertEqual(response.content.decode(), "") + self.assertEqual(response.headers["Content-Length"], "0") user: User = User.objects.get(email=self.CONFIG_EMAIL) self.assertEqual(