diff --git a/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentCounter.tsx b/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentCounter.tsx index e0d63e22b..9a6f845f8 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentCounter.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsOptions/SettingsOptionCardContentCounter.tsx @@ -51,6 +51,7 @@ export const SettingsOptionCardContentCounter = ({ onChange={onChange} minValue={minValue} maxValue={maxValue} + disabled={disabled} /> ); diff --git a/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentCounter.stories.tsx b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentCounter.stories.tsx new file mode 100644 index 000000000..3398e206c --- /dev/null +++ b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentCounter.stories.tsx @@ -0,0 +1,80 @@ +import { SettingsOptionCardContentCounter } from '@/settings/components/SettingsOptions/SettingsOptionCardContentCounter'; +import styled from '@emotion/styled'; +import { Meta, StoryObj } from '@storybook/react'; +import { useState } from 'react'; +import { ComponentDecorator, IconUsers } from 'twenty-ui'; + +const StyledContainer = styled.div` + width: 480px; +`; + +const SettingsOptionCardContentCounterWrapper = ( + args: React.ComponentProps, +) => { + const [value, setValue] = useState(args.value); + + return ( + + + + ); +}; + +const meta: Meta = { + title: 'Modules/Settings/SettingsOptionCardContentCounter', + component: SettingsOptionCardContentCounterWrapper, + decorators: [ComponentDecorator], + parameters: { + maxWidth: 800, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + Icon: IconUsers, + title: 'Team Members', + description: 'Set the maximum number of team members', + value: 5, + minValue: 1, + maxValue: 10, + }, + argTypes: { + Icon: { control: false }, + onChange: { control: false }, + }, +}; + +export const WithoutIcon: Story = { + args: { + title: 'Items Per Page', + description: 'Configure the number of items shown per page', + value: 20, + minValue: 10, + maxValue: 50, + }, +}; + +export const Disabled: Story = { + args: { + Icon: IconUsers, + title: 'Disabled Counter', + description: 'This counter is currently disabled', + value: 3, + disabled: true, + minValue: 1, + maxValue: 10, + }, +}; diff --git a/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentSelect.stories.tsx b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentSelect.stories.tsx new file mode 100644 index 000000000..4f8a1a669 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentSelect.stories.tsx @@ -0,0 +1,142 @@ +import { SettingsOptionCardContentSelect } from '@/settings/components/SettingsOptions/SettingsOptionCardContentSelect'; +import styled from '@emotion/styled'; +import { Meta, StoryObj } from '@storybook/react'; +import { useState } from 'react'; +import { + ComponentDecorator, + IconLanguage, + IconLayoutKanban, + IconList, + IconNotes, + IconTable, + IconUsers, +} from 'twenty-ui'; + +const StyledContainer = styled.div` + width: 480px; +`; + +type SelectValue = string | number | boolean | null; + +const SettingsOptionCardContentSelectWrapper = ( + args: React.ComponentProps>, +) => { + const [value, setValue] = useState(args.value); + + return ( + + setValue(newValue as Value)} + Icon={args.Icon} + title={args.title} + description={args.description} + divider={args.divider} + disabled={args.disabled} + options={args.options} + selectClassName={args.selectClassName} + dropdownId={args.dropdownId} + fullWidth={args.fullWidth} + /> + + ); +}; + +const meta: Meta = { + title: 'Modules/Settings/SettingsOptionCardContentSelect', + component: SettingsOptionCardContentSelectWrapper, + decorators: [ComponentDecorator], + parameters: { + maxWidth: 800, + }, +}; + +export default meta; +type Story = StoryObj; + +export const StringSelect: Story = { + args: { + Icon: IconLanguage, + title: 'Language', + description: 'Select your preferred language', + value: 'en', + options: [ + { value: 'en', label: 'English' }, + { value: 'fr', label: 'French' }, + { value: 'es', label: 'Spanish' }, + ], + dropdownId: 'language-select', + }, + argTypes: { + Icon: { control: false }, + onChange: { control: false }, + }, +}; + +export const NumberSelect: Story = { + args: { + Icon: IconNotes, + title: 'Items Per Page', + description: 'Number of items to display per page', + value: 25, + options: [ + { value: 10, label: '10' }, + { value: 25, label: '25' }, + { value: 50, label: '50' }, + { value: 100, label: '100' }, + ], + dropdownId: 'page-size-select', + }, +}; + +export const WithIconOptions: Story = { + args: { + Icon: IconUsers, + title: 'Team View', + description: 'Select how to display team members', + value: 'grid', + options: [ + { value: 'list', label: 'List View', Icon: IconList }, + { value: 'kanban', label: 'Kanban View', Icon: IconLayoutKanban }, + { value: 'table', label: 'Table View', Icon: IconTable }, + ], + dropdownId: 'view-select', + }, +}; + +export const Disabled: Story = { + args: { + Icon: IconUsers, + title: 'Disabled Select', + description: 'This select is currently disabled', + disabled: true, + value: 'option1', + options: [ + { value: 'option1', label: 'Option 1' }, + { value: 'option2', label: 'Option 2' }, + { value: 'option3', label: 'Option 3' }, + ], + dropdownId: 'disabled-select', + }, +}; + +export const FullWidth: Story = { + args: { + title: 'Full Width Select', + description: 'This select uses the full width of the dropdown', + value: 'short', + options: [ + { value: 'short', label: 'Short option' }, + { + value: 'very-long', + label: 'This is a very long option that needs more space', + }, + { + value: 'another-long', + label: 'Another long option that extends the width', + }, + ], + dropdownId: 'full-width-select', + fullWidth: true, + }, +}; diff --git a/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentToggle.stories.tsx b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentToggle.stories.tsx new file mode 100644 index 000000000..9260104f9 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/components/SettingsOptions/__stories__/SettingsOptionCardContentToggle.stories.tsx @@ -0,0 +1,97 @@ +import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle'; +import styled from '@emotion/styled'; +import { Meta, StoryObj } from '@storybook/react'; +import { useState } from 'react'; +import { + ComponentDecorator, + IconBell, + IconLock, + IconRobot, + IconUsers, +} from 'twenty-ui'; + +const StyledContainer = styled.div` + width: 480px; +`; + +const SettingsOptionCardContentToggleWrapper = ( + args: React.ComponentProps, +) => { + const [checked, setChecked] = useState(args.checked); + + return ( + + + + ); +}; + +const meta: Meta = { + title: 'Modules/Settings/SettingsOptionCardContentToggle', + component: SettingsOptionCardContentToggleWrapper, + decorators: [ComponentDecorator], + parameters: { + maxWidth: 800, + }, +}; + +export default meta; +type Story = StoryObj; + +export const Default: Story = { + args: { + Icon: IconBell, + title: 'Notifications', + description: 'Receive notifications about important updates', + checked: true, + }, + argTypes: { + Icon: { control: false }, + onChange: { control: false }, + }, +}; + +export const Disabled: Story = { + args: { + Icon: IconLock, + title: 'Locked Setting', + description: 'This setting is currently unavailable', + checked: false, + disabled: true, + }, +}; + +export const AdvancedMode: Story = { + args: { + Icon: IconRobot, + title: 'Advanced Features', + description: 'Enable experimental features', + checked: true, + advancedMode: true, + }, +}; + +export const WithoutIcon: Story = { + args: { + title: 'Simple Toggle', + description: 'A basic toggle without an icon', + checked: true, + }, +}; + +export const WithoutDescription: Story = { + args: { + Icon: IconUsers, + title: 'Team Access', + checked: false, + }, +}; diff --git a/packages/twenty-website/src/content/developers/self-hosting/docker-compose.mdx b/packages/twenty-website/src/content/developers/self-hosting/docker-compose.mdx index 7ff62a44c..e63a706c7 100644 --- a/packages/twenty-website/src/content/developers/self-hosting/docker-compose.mdx +++ b/packages/twenty-website/src/content/developers/self-hosting/docker-compose.mdx @@ -105,6 +105,14 @@ By default, Twenty runs on `localhost` at port `3000`. To access it via an exter - **Domain/IP:** This is the domain name or IP address where your application is accessible. - **Port:** Include the port number if you're not using the default ports (`80` for `http`, `443` for `https`). +### SSL Requirements + +SSL (HTTPS) is required for certain browser features to work properly. While these features might work during local development (as browsers treat localhost differently), a proper SSL setup is needed when hosting Twenty on a regular domain. + +For example, the clipboard API might require a secure context - some features like copy buttons throughout the application might not work without HTTPS enabled. + +We strongly recommend setting up Twenty behind a reverse proxy with SSL termination for optimal security and functionality. + #### Configuring `SERVER_URL` 1. **Determine Your Access URL**