@kelpie/ui 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/resources/attendances.d.ts +13 -0
- package/dist/api/resources/attendances.d.ts.map +1 -0
- package/dist/api/resources/attendances.js +34 -0
- package/dist/api/resources/attendances.js.map +1 -0
- package/dist/api/resources/eventAssociations.d.ts +12 -0
- package/dist/api/resources/eventAssociations.d.ts.map +1 -0
- package/dist/api/resources/eventAssociations.js +25 -0
- package/dist/api/resources/eventAssociations.js.map +1 -0
- package/dist/api/resources/events.d.ts +17 -0
- package/dist/api/resources/events.d.ts.map +1 -0
- package/dist/api/resources/events.js +40 -0
- package/dist/api/resources/events.js.map +1 -0
- package/dist/api/resources/handbookSeed.d.ts +11 -0
- package/dist/api/resources/handbookSeed.d.ts.map +1 -0
- package/dist/api/resources/handbookSeed.js +43 -0
- package/dist/api/resources/handbookSeed.js.map +1 -0
- package/dist/api/resources/moduleSettings.d.ts +10 -0
- package/dist/api/resources/moduleSettings.d.ts.map +1 -1
- package/dist/api/resources/moduleSettings.js +21 -0
- package/dist/api/resources/moduleSettings.js.map +1 -1
- package/dist/api/resources/planItems.d.ts +4 -4
- package/dist/api/resources/planItems.d.ts.map +1 -1
- package/dist/api/resources/planItems.js +1 -1
- package/dist/api/resources/planItems.js.map +1 -1
- package/dist/api/resources/publicConfig.js +3 -3
- package/dist/api/resources/sampleData.d.ts.map +1 -1
- package/dist/api/resources/sampleData.js +2 -0
- package/dist/api/resources/sampleData.js.map +1 -1
- package/dist/api/resources/session.d.ts +22 -1
- package/dist/api/resources/session.d.ts.map +1 -1
- package/dist/api/resources/session.js +43 -1
- package/dist/api/resources/session.js.map +1 -1
- package/dist/api/resources/workspace.d.ts.map +1 -1
- package/dist/api/resources/workspace.js +2 -3
- package/dist/api/resources/workspace.js.map +1 -1
- package/dist/app/KelpieApp.d.ts.map +1 -1
- package/dist/app/KelpieApp.js +5 -1
- package/dist/app/KelpieApp.js.map +1 -1
- package/dist/components/ActivitiesPanel.d.ts.map +1 -1
- package/dist/components/ActivitiesPanel.js +2 -0
- package/dist/components/ActivitiesPanel.js.map +1 -1
- package/dist/components/AddressesField.d.ts +23 -0
- package/dist/components/AddressesField.d.ts.map +1 -0
- package/dist/components/AddressesField.js +215 -0
- package/dist/components/AddressesField.js.map +1 -0
- package/dist/components/CountrySearch.d.ts +16 -0
- package/dist/components/CountrySearch.d.ts.map +1 -0
- package/dist/components/CountrySearch.js +30 -0
- package/dist/components/CountrySearch.js.map +1 -0
- package/dist/components/EnvironmentBanner.d.ts +0 -12
- package/dist/components/EnvironmentBanner.d.ts.map +1 -1
- package/dist/components/EnvironmentBanner.js +21 -6
- package/dist/components/EnvironmentBanner.js.map +1 -1
- package/dist/components/InlineEdit.d.ts +7 -1
- package/dist/components/InlineEdit.d.ts.map +1 -1
- package/dist/components/InlineEdit.js +8 -1
- package/dist/components/InlineEdit.js.map +1 -1
- package/dist/components/LinkedEventsPanel.d.ts +11 -0
- package/dist/components/LinkedEventsPanel.d.ts.map +1 -0
- package/dist/components/LinkedEventsPanel.js +18 -0
- package/dist/components/LinkedEventsPanel.js.map +1 -0
- package/dist/components/NotesPanel.d.ts +4 -6
- package/dist/components/NotesPanel.d.ts.map +1 -1
- package/dist/components/NotesPanel.js +39 -3
- package/dist/components/NotesPanel.js.map +1 -1
- package/dist/components/PlanAttention.d.ts.map +1 -1
- package/dist/components/PlanAttention.js +3 -2
- package/dist/components/PlanAttention.js.map +1 -1
- package/dist/components/PlanPanel.d.ts +3 -3
- package/dist/components/PlanPanel.d.ts.map +1 -1
- package/dist/components/Shell.d.ts.map +1 -1
- package/dist/components/Shell.js +8 -2
- package/dist/components/Shell.js.map +1 -1
- package/dist/components/SocialNetworkIcon.d.ts +17 -0
- package/dist/components/SocialNetworkIcon.d.ts.map +1 -0
- package/dist/components/SocialNetworkIcon.js +39 -0
- package/dist/components/SocialNetworkIcon.js.map +1 -0
- package/dist/components/SocialProfilesField.d.ts +8 -0
- package/dist/components/SocialProfilesField.d.ts.map +1 -1
- package/dist/components/SocialProfilesField.js +19 -5
- package/dist/components/SocialProfilesField.js.map +1 -1
- package/dist/components/TimezoneSearch.d.ts +21 -0
- package/dist/components/TimezoneSearch.d.ts.map +1 -0
- package/dist/components/TimezoneSearch.js +27 -0
- package/dist/components/TimezoneSearch.js.map +1 -0
- package/dist/components/WorkspaceSwitcher.d.ts +8 -0
- package/dist/components/WorkspaceSwitcher.d.ts.map +1 -0
- package/dist/components/WorkspaceSwitcher.js +67 -0
- package/dist/components/WorkspaceSwitcher.js.map +1 -0
- package/dist/components/environmentTone.d.ts +10 -0
- package/dist/components/environmentTone.d.ts.map +1 -0
- package/dist/components/environmentTone.js +35 -0
- package/dist/components/environmentTone.js.map +1 -0
- package/dist/index.d.ts +21 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/timezones.d.ts +17 -0
- package/dist/lib/timezones.d.ts.map +1 -0
- package/dist/lib/timezones.js +39 -0
- package/dist/lib/timezones.js.map +1 -0
- package/dist/pages/CompaniesPage.d.ts.map +1 -1
- package/dist/pages/CompaniesPage.js +12 -11
- package/dist/pages/CompaniesPage.js.map +1 -1
- package/dist/pages/CompanyDetail.d.ts.map +1 -1
- package/dist/pages/CompanyDetail.js +23 -12
- package/dist/pages/CompanyDetail.js.map +1 -1
- package/dist/pages/DealDetail.d.ts.map +1 -1
- package/dist/pages/DealDetail.js +5 -1
- package/dist/pages/DealDetail.js.map +1 -1
- package/dist/pages/DecisionsPage.d.ts.map +1 -1
- package/dist/pages/DecisionsPage.js +7 -0
- package/dist/pages/DecisionsPage.js.map +1 -1
- package/dist/pages/EnquiryDetail.d.ts.map +1 -1
- package/dist/pages/EnquiryDetail.js +5 -1
- package/dist/pages/EnquiryDetail.js.map +1 -1
- package/dist/pages/EventDetail.d.ts +2 -0
- package/dist/pages/EventDetail.d.ts.map +1 -0
- package/dist/pages/EventDetail.js +332 -0
- package/dist/pages/EventDetail.js.map +1 -0
- package/dist/pages/EventsPage.d.ts +2 -0
- package/dist/pages/EventsPage.d.ts.map +1 -0
- package/dist/pages/EventsPage.js +176 -0
- package/dist/pages/EventsPage.js.map +1 -0
- package/dist/pages/ListDetail.d.ts.map +1 -1
- package/dist/pages/ListDetail.js +17 -0
- package/dist/pages/ListDetail.js.map +1 -1
- package/dist/pages/OpportunityDetail.d.ts.map +1 -1
- package/dist/pages/OpportunityDetail.js +5 -1
- package/dist/pages/OpportunityDetail.js.map +1 -1
- package/dist/pages/PartnershipDetail.d.ts.map +1 -1
- package/dist/pages/PartnershipDetail.js +5 -1
- package/dist/pages/PartnershipDetail.js.map +1 -1
- package/dist/pages/PeoplePage.d.ts.map +1 -1
- package/dist/pages/PeoplePage.js +13 -5
- package/dist/pages/PeoplePage.js.map +1 -1
- package/dist/pages/PersonDetail.d.ts.map +1 -1
- package/dist/pages/PersonDetail.js +94 -28
- package/dist/pages/PersonDetail.js.map +1 -1
- package/dist/pages/PlanningPage.d.ts.map +1 -1
- package/dist/pages/PlanningPage.js +6 -3
- package/dist/pages/PlanningPage.js.map +1 -1
- package/dist/pages/RaiseDetail.d.ts.map +1 -1
- package/dist/pages/RaiseDetail.js +5 -1
- package/dist/pages/RaiseDetail.js.map +1 -1
- package/dist/pages/RoleDetail.d.ts.map +1 -1
- package/dist/pages/RoleDetail.js +4 -1
- package/dist/pages/RoleDetail.js.map +1 -1
- package/dist/pages/SearchPage.d.ts.map +1 -1
- package/dist/pages/SearchPage.js +2 -1
- package/dist/pages/SearchPage.js.map +1 -1
- package/dist/pages/account/PreferencesPage.d.ts.map +1 -1
- package/dist/pages/account/PreferencesPage.js +2 -28
- package/dist/pages/account/PreferencesPage.js.map +1 -1
- package/dist/pages/admin/DataPage.js +10 -9
- package/dist/pages/admin/DataPage.js.map +1 -1
- package/dist/pages/admin/FieldsPage.js +1 -1
- package/dist/pages/admin/FieldsPage.js.map +1 -1
- package/dist/pages/admin/ModulesPage.d.ts.map +1 -1
- package/dist/pages/admin/ModulesPage.js +1 -0
- package/dist/pages/admin/ModulesPage.js.map +1 -1
- package/dist/pages/admin/WorkspaceSettingsPage.d.ts +12 -0
- package/dist/pages/admin/WorkspaceSettingsPage.d.ts.map +1 -1
- package/dist/pages/admin/WorkspaceSettingsPage.js +2 -21
- package/dist/pages/admin/WorkspaceSettingsPage.js.map +1 -1
- package/dist/pages/auth/AuthLayout.d.ts +5 -4
- package/dist/pages/auth/AuthLayout.d.ts.map +1 -1
- package/dist/pages/auth/AuthLayout.js +7 -5
- package/dist/pages/auth/AuthLayout.js.map +1 -1
- package/dist/pages/auth/RegionSwitcher.d.ts +10 -0
- package/dist/pages/auth/RegionSwitcher.d.ts.map +1 -0
- package/dist/pages/auth/RegionSwitcher.js +28 -0
- package/dist/pages/auth/RegionSwitcher.js.map +1 -0
- package/dist/pages/auth/SignInPage.d.ts.map +1 -1
- package/dist/pages/auth/SignInPage.js +3 -1
- package/dist/pages/auth/SignInPage.js.map +1 -1
- package/dist/pages/auth/SignUpPage.d.ts.map +1 -1
- package/dist/pages/auth/SignUpPage.js +7 -0
- package/dist/pages/auth/SignUpPage.js.map +1 -1
- package/dist/pages/auth/regionHref.d.ts +6 -0
- package/dist/pages/auth/regionHref.d.ts.map +1 -0
- package/dist/pages/auth/regionHref.js +8 -0
- package/dist/pages/auth/regionHref.js.map +1 -0
- package/dist/pages/dashboard/DashboardPage.d.ts +8 -0
- package/dist/pages/dashboard/DashboardPage.d.ts.map +1 -1
- package/dist/pages/dashboard/DashboardPage.js +5 -13
- package/dist/pages/dashboard/DashboardPage.js.map +1 -1
- package/dist/pages/dashboard/attention.d.ts +1 -8
- package/dist/pages/dashboard/attention.d.ts.map +1 -1
- package/dist/pages/dashboard/attention.js +21 -54
- package/dist/pages/dashboard/attention.js.map +1 -1
- package/dist/pages/dashboard/sections.d.ts.map +1 -1
- package/dist/pages/dashboard/sections.js +3 -2
- package/dist/pages/dashboard/sections.js.map +1 -1
- package/dist/pages/forms/FormActions.d.ts.map +1 -1
- package/dist/pages/forms/FormActions.js +7 -3
- package/dist/pages/forms/FormActions.js.map +1 -1
- package/dist/pages/onboarding/HandbookStepPage.d.ts +4 -8
- package/dist/pages/onboarding/HandbookStepPage.d.ts.map +1 -1
- package/dist/pages/onboarding/HandbookStepPage.js +13 -13
- package/dist/pages/onboarding/HandbookStepPage.js.map +1 -1
- package/dist/pages/onboarding/InvitesStepPage.d.ts.map +1 -1
- package/dist/pages/onboarding/InvitesStepPage.js +13 -7
- package/dist/pages/onboarding/InvitesStepPage.js.map +1 -1
- package/dist/pages/onboarding/ModulesStepPage.d.ts +11 -0
- package/dist/pages/onboarding/ModulesStepPage.d.ts.map +1 -0
- package/dist/pages/onboarding/ModulesStepPage.js +80 -0
- package/dist/pages/onboarding/ModulesStepPage.js.map +1 -0
- package/dist/pages/onboarding/OnboardingNav.d.ts +17 -0
- package/dist/pages/onboarding/OnboardingNav.d.ts.map +1 -0
- package/dist/pages/onboarding/OnboardingNav.js +37 -0
- package/dist/pages/onboarding/OnboardingNav.js.map +1 -0
- package/dist/pages/onboarding/OrganisationStepPage.d.ts +13 -0
- package/dist/pages/onboarding/OrganisationStepPage.d.ts.map +1 -0
- package/dist/pages/onboarding/OrganisationStepPage.js +59 -0
- package/dist/pages/onboarding/OrganisationStepPage.js.map +1 -0
- package/dist/pages/onboarding/WorkspaceStepPage.d.ts.map +1 -1
- package/dist/pages/onboarding/WorkspaceStepPage.js +25 -20
- package/dist/pages/onboarding/WorkspaceStepPage.js.map +1 -1
- package/dist/pages/onboarding/handbookTemplates.d.ts +19 -0
- package/dist/pages/onboarding/handbookTemplates.d.ts.map +1 -0
- package/dist/pages/onboarding/handbookTemplates.js +57 -0
- package/dist/pages/onboarding/handbookTemplates.js.map +1 -0
- package/dist/pages/onboarding/onboardingModules.d.ts +23 -0
- package/dist/pages/onboarding/onboardingModules.d.ts.map +1 -0
- package/dist/pages/onboarding/onboardingModules.js +153 -0
- package/dist/pages/onboarding/onboardingModules.js.map +1 -0
- package/dist/pages/onboarding/onboardingRerun.d.ts +21 -0
- package/dist/pages/onboarding/onboardingRerun.d.ts.map +1 -0
- package/dist/pages/onboarding/onboardingRerun.js +33 -0
- package/dist/pages/onboarding/onboardingRerun.js.map +1 -0
- package/package.json +4 -3
- package/src/api/resources/attendances.ts +54 -0
- package/src/api/resources/eventAssociations.ts +43 -0
- package/src/api/resources/events.ts +70 -0
- package/src/api/resources/handbookSeed.ts +63 -0
- package/src/api/resources/moduleSettings.ts +25 -0
- package/src/api/resources/planItems.ts +5 -5
- package/src/api/resources/publicConfig.ts +3 -3
- package/src/api/resources/sampleData.ts +2 -0
- package/src/api/resources/session.ts +59 -0
- package/src/api/resources/workspace.ts +2 -3
- package/src/app/KelpieApp.tsx +11 -3
- package/src/components/ActivitiesPanel.tsx +2 -0
- package/src/components/AddressesField.tsx +502 -0
- package/src/components/CountrySearch.tsx +71 -0
- package/src/components/EnvironmentBanner.tsx +23 -6
- package/src/components/InlineEdit.tsx +35 -1
- package/src/components/LinkedEventsPanel.tsx +50 -0
- package/src/components/NotesPanel.tsx +132 -15
- package/src/components/PlanAttention.tsx +5 -4
- package/src/components/PlanPanel.tsx +3 -3
- package/src/components/Shell.tsx +16 -1
- package/src/components/SocialNetworkIcon.tsx +88 -0
- package/src/components/SocialProfilesField.tsx +57 -10
- package/src/components/TimezoneSearch.tsx +67 -0
- package/src/components/WorkspaceSwitcher.tsx +136 -0
- package/src/components/environmentTone.ts +40 -0
- package/src/index.ts +42 -3
- package/src/lib/timezones.ts +43 -0
- package/src/pages/CompaniesPage.tsx +14 -13
- package/src/pages/CompanyDetail.tsx +59 -27
- package/src/pages/DealDetail.tsx +5 -0
- package/src/pages/DecisionsPage.tsx +7 -0
- package/src/pages/EnquiryDetail.tsx +7 -0
- package/src/pages/EventDetail.tsx +794 -0
- package/src/pages/EventsPage.tsx +382 -0
- package/src/pages/ListDetail.tsx +24 -0
- package/src/pages/OpportunityDetail.tsx +7 -0
- package/src/pages/PartnershipDetail.tsx +7 -0
- package/src/pages/PeoplePage.tsx +18 -5
- package/src/pages/PersonDetail.tsx +300 -100
- package/src/pages/PlanningPage.tsx +17 -14
- package/src/pages/RaiseDetail.tsx +5 -0
- package/src/pages/RoleDetail.tsx +8 -0
- package/src/pages/SearchPage.tsx +2 -1
- package/src/pages/account/PreferencesPage.tsx +2 -37
- package/src/pages/admin/DataPage.tsx +63 -21
- package/src/pages/admin/FieldsPage.tsx +1 -1
- package/src/pages/admin/ModulesPage.tsx +1 -0
- package/src/pages/admin/WorkspaceSettingsPage.tsx +10 -33
- package/src/pages/auth/AuthLayout.tsx +8 -4
- package/src/pages/auth/RegionSwitcher.tsx +56 -0
- package/src/pages/auth/SignInPage.tsx +10 -6
- package/src/pages/auth/SignUpPage.tsx +25 -0
- package/src/pages/auth/regionHref.ts +10 -0
- package/src/pages/dashboard/DashboardPage.tsx +16 -48
- package/src/pages/dashboard/attention.ts +24 -78
- package/src/pages/dashboard/sections.tsx +8 -2
- package/src/pages/forms/FormActions.tsx +14 -8
- package/src/pages/onboarding/HandbookStepPage.tsx +21 -24
- package/src/pages/onboarding/InvitesStepPage.tsx +27 -19
- package/src/pages/onboarding/ModulesStepPage.tsx +145 -0
- package/src/pages/onboarding/OnboardingNav.tsx +97 -0
- package/src/pages/onboarding/OrganisationStepPage.tsx +130 -0
- package/src/pages/onboarding/WorkspaceStepPage.tsx +53 -38
- package/src/pages/onboarding/handbookTemplates.ts +77 -0
- package/src/pages/onboarding/onboardingModules.ts +202 -0
- package/src/pages/onboarding/onboardingRerun.ts +41 -0
- package/src/styles.css +30 -0
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
useConvertPipelineRecord,
|
|
12
12
|
} from '../api/resources/conversions.ts'
|
|
13
13
|
import { useMembers } from '../api/resources/members.ts'
|
|
14
|
+
import { useModuleEnabled } from '../api/resources/moduleSettings.ts'
|
|
14
15
|
import { usePeople } from '../api/resources/people.ts'
|
|
15
16
|
import { usePipelineStages } from '../api/resources/pipelineStages.ts'
|
|
16
17
|
import { useRecordPlanItems } from '../api/resources/planItems.ts'
|
|
@@ -27,6 +28,7 @@ import { CustomFieldsPanel } from '../components/CustomFieldsPanel.tsx'
|
|
|
27
28
|
import { useHasCustomFields } from '../components/useHasCustomFields.ts'
|
|
28
29
|
import { InlineEdit } from '../components/InlineEdit.tsx'
|
|
29
30
|
import { ListsPanel } from '../components/ListsPanel.tsx'
|
|
31
|
+
import { LinkedEventsPanel } from '../components/LinkedEventsPanel.tsx'
|
|
30
32
|
import { NotesPanel } from '../components/NotesPanel.tsx'
|
|
31
33
|
import { PlanAttention } from '../components/PlanAttention.tsx'
|
|
32
34
|
import { PlanPanel } from '../components/PlanPanel.tsx'
|
|
@@ -69,6 +71,7 @@ export function RaiseDetail(): React.JSX.Element {
|
|
|
69
71
|
const deleteRaise = useDeleteRaise()
|
|
70
72
|
const moduleTabs = inSlotOrder(useRecordTabs('raise'))
|
|
71
73
|
const hasCustomFields = useHasCustomFields('raise')
|
|
74
|
+
const eventsEnabled = useModuleEnabled('events')
|
|
72
75
|
const [activeTab, setActiveTab] = useState('overview')
|
|
73
76
|
const [showConvert, setShowConvert] = useState(false)
|
|
74
77
|
|
|
@@ -92,6 +95,7 @@ export function RaiseDetail(): React.JSX.Element {
|
|
|
92
95
|
{ id: 'notes', label: 'Notes' },
|
|
93
96
|
{ id: 'decisions', label: 'Decisions' },
|
|
94
97
|
{ id: 'lists', label: 'Lists' },
|
|
98
|
+
...(eventsEnabled ? [{ id: 'events', label: 'Events' }] : []),
|
|
95
99
|
...moduleTabs.map((tab) => ({ id: tab.id, label: tab.label })),
|
|
96
100
|
]
|
|
97
101
|
const active = tabs.some((tab) => tab.id === activeTab) ? activeTab : 'overview'
|
|
@@ -162,6 +166,7 @@ export function RaiseDetail(): React.JSX.Element {
|
|
|
162
166
|
{active === 'notes' && <NotesPanel targetType="raise" targetId={record.id} />}
|
|
163
167
|
{active === 'decisions' && <DecisionsPanel targetType="raise" targetId={record.id} />}
|
|
164
168
|
{active === 'lists' && <ListsPanel targetType="raise" targetId={record.id} />}
|
|
169
|
+
{active === 'events' && <LinkedEventsPanel targetType="raise" targetId={record.id} />}
|
|
165
170
|
{moduleTab?.render({ objectType: 'raise', recordId: record.id })}
|
|
166
171
|
</RecordTabs>
|
|
167
172
|
</div>
|
package/src/pages/RoleDetail.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { Link, useNavigate, useParams } from 'react-router'
|
|
|
7
7
|
import { usePatch } from '../api/resource.ts'
|
|
8
8
|
import type { PatchResult } from '../api/resource.ts'
|
|
9
9
|
import { useCandidates, useCreateCandidate, useDeleteCandidate } from '../api/resources/candidates.ts'
|
|
10
|
+
import { useModuleEnabled } from '../api/resources/moduleSettings.ts'
|
|
10
11
|
import { useCreateNote, useDeleteNote, useUpdateNote } from '../api/resources/notes.ts'
|
|
11
12
|
import { useCreatePerson, usePeople } from '../api/resources/people.ts'
|
|
12
13
|
import { useDeleteRole, useRole, useUpdateRole } from '../api/resources/roles.ts'
|
|
@@ -15,6 +16,7 @@ import { Chip } from '../components/Chip.tsx'
|
|
|
15
16
|
import { DeleteRecord } from '../components/DeleteRecord.tsx'
|
|
16
17
|
import { EntitySearch } from '../components/EntitySearch.tsx'
|
|
17
18
|
import { InlineEdit } from '../components/InlineEdit.tsx'
|
|
19
|
+
import { LinkedEventsPanel } from '../components/LinkedEventsPanel.tsx'
|
|
18
20
|
import { Paginator } from '../components/Paginator.tsx'
|
|
19
21
|
import { ErrorPanel, LoadingPanel, NotFoundPanel } from '../components/QueryState.tsx'
|
|
20
22
|
import { SectionHeader } from '../components/SectionHeader.tsx'
|
|
@@ -46,6 +48,7 @@ export function RoleDetail(): React.JSX.Element {
|
|
|
46
48
|
const navigate = useNavigate()
|
|
47
49
|
const { record, isLoading, isNotFound, error } = useRole(id)
|
|
48
50
|
const deleteRole = useDeleteRole()
|
|
51
|
+
const eventsEnabled = useModuleEnabled('events')
|
|
49
52
|
|
|
50
53
|
if (isNotFound) {
|
|
51
54
|
return <NotFoundPanel label="Role" backTo="/hiring" />
|
|
@@ -89,6 +92,11 @@ export function RoleDetail(): React.JSX.Element {
|
|
|
89
92
|
</div>
|
|
90
93
|
|
|
91
94
|
<RoleCandidates role={record} />
|
|
95
|
+
{eventsEnabled && (
|
|
96
|
+
<div className="mt-8">
|
|
97
|
+
<LinkedEventsPanel targetType="role" targetId={record.id} />
|
|
98
|
+
</div>
|
|
99
|
+
)}
|
|
92
100
|
</div>
|
|
93
101
|
)
|
|
94
102
|
}
|
package/src/pages/SearchPage.tsx
CHANGED
|
@@ -24,6 +24,7 @@ const COLLECTIONS: Readonly<Record<SearchCollection, { label: string; path: (id:
|
|
|
24
24
|
opportunity: { label: 'Opportunities', path: (id) => `/opportunities/${id}` },
|
|
25
25
|
raise: { label: 'Fundraising', path: (id) => `/fundraising/${id}` },
|
|
26
26
|
partnership: { label: 'Partnerships', path: (id) => `/partnerships/${id}` },
|
|
27
|
+
event: { label: 'Events', path: (id) => `/events/${id}` },
|
|
27
28
|
// Decisions have no detail page of their own, in the mockup or here. The global
|
|
28
29
|
// list is where one is read.
|
|
29
30
|
decision: { label: 'Decisions', path: () => '/decisions' },
|
|
@@ -39,7 +40,7 @@ export function SearchPage(): React.JSX.Element {
|
|
|
39
40
|
<div className="animate-fade-in py-16 text-center">
|
|
40
41
|
<p className="text-[15px] font-medium text-ink">Search Kelpie</p>
|
|
41
42
|
<p className="mt-1 text-[13px] text-ink-muted">
|
|
42
|
-
Find people, companies, deals, raises, decisions, and handbook pages.
|
|
43
|
+
Find people, companies, deals, events, raises, decisions, and handbook pages.
|
|
43
44
|
</p>
|
|
44
45
|
</div>
|
|
45
46
|
)
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
useTheme,
|
|
9
9
|
useUpdateAccountPreferences,
|
|
10
10
|
} from '../../api/resources/account.ts'
|
|
11
|
-
import { EntitySearch } from '../../components/EntitySearch.tsx'
|
|
12
11
|
import { PageHeader } from '../../components/PageHeader.tsx'
|
|
13
12
|
import { ErrorPanel, LoadingPanel } from '../../components/QueryState.tsx'
|
|
13
|
+
import { TimezoneSearch } from '../../components/TimezoneSearch.tsx'
|
|
14
14
|
import { Field } from './Field.tsx'
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -27,31 +27,6 @@ const THEME_LABELS: Readonly<Record<ThemePreference, string>> = {
|
|
|
27
27
|
dark: 'Dark',
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* Every zone this runtime's ICU knows, matching what the server's
|
|
32
|
-
* `timezoneSchema` will accept. Falls back to the zones the mockup offered if
|
|
33
|
-
* `Intl.supportedValuesOf` is missing, for a browser old enough to lack it.
|
|
34
|
-
*
|
|
35
|
-
* `UTC` is prepended because `supportedValuesOf` omits it in some engines even
|
|
36
|
-
* though ECMA-402 guarantees `Intl.DateTimeFormat` accepts it as a zone name.
|
|
37
|
-
* Without this, a very common choice would be searchable only by accident of
|
|
38
|
-
* already being the stored value.
|
|
39
|
-
*/
|
|
40
|
-
const ALL_TIMEZONES: readonly string[] = (() => {
|
|
41
|
-
try {
|
|
42
|
-
return ['UTC', ...Intl.supportedValuesOf('timeZone')]
|
|
43
|
-
} catch {
|
|
44
|
-
return [
|
|
45
|
-
'UTC',
|
|
46
|
-
'Australia/Sydney',
|
|
47
|
-
'Australia/Melbourne',
|
|
48
|
-
'America/Los_Angeles',
|
|
49
|
-
'America/New_York',
|
|
50
|
-
'Europe/London',
|
|
51
|
-
]
|
|
52
|
-
}
|
|
53
|
-
})()
|
|
54
|
-
|
|
55
30
|
export function PreferencesPage(): React.JSX.Element {
|
|
56
31
|
const { preferences, isLoading, error } = useAccountPreferences()
|
|
57
32
|
|
|
@@ -79,8 +54,6 @@ function PreferencesForm({
|
|
|
79
54
|
const [productUpdates, setProductUpdates] = useState(preferences.productUpdates)
|
|
80
55
|
const [saved, setSaved] = useState(false)
|
|
81
56
|
|
|
82
|
-
const zones = ALL_TIMEZONES.includes(timezone) ? ALL_TIMEZONES : [timezone, ...ALL_TIMEZONES]
|
|
83
|
-
|
|
84
57
|
function save(event: FormEvent): void {
|
|
85
58
|
event.preventDefault()
|
|
86
59
|
setSaved(false)
|
|
@@ -135,15 +108,7 @@ function PreferencesForm({
|
|
|
135
108
|
label="Timezone"
|
|
136
109
|
hint="Stored on your account. Dates across Kelpie use this zone."
|
|
137
110
|
>
|
|
138
|
-
<
|
|
139
|
-
options={zones.map((zone) => ({ id: zone, label: zone }))}
|
|
140
|
-
value={timezone}
|
|
141
|
-
onChange={setTimezone}
|
|
142
|
-
placeholder="Search time zones…"
|
|
143
|
-
limit={20}
|
|
144
|
-
required
|
|
145
|
-
size="md"
|
|
146
|
-
/>
|
|
111
|
+
<TimezoneSearch value={timezone} onChange={setTimezone} required size="md" />
|
|
147
112
|
</Field>
|
|
148
113
|
</div>
|
|
149
114
|
|
|
@@ -1014,17 +1014,17 @@ function messageOf(error: Error | null | undefined): string | null {
|
|
|
1014
1014
|
/**
|
|
1015
1015
|
* One button that fills the workspace with a small demo fixture.
|
|
1016
1016
|
*
|
|
1017
|
-
* The
|
|
1018
|
-
*
|
|
1019
|
-
* a plain error line.
|
|
1017
|
+
* The first click opens a warning. Confirm is what POSTs. Existing records
|
|
1018
|
+
* stay; a sample email or domain that is already present fails the install.
|
|
1020
1019
|
*/
|
|
1021
1020
|
function SampleDataSection(): ReactNode {
|
|
1022
1021
|
const { session } = useSession()
|
|
1023
1022
|
const workspaceId = session?.workspaceId ?? null
|
|
1024
1023
|
const install = useInstallSampleData()
|
|
1025
1024
|
const [counts, setCounts] = useState<SampleDataCounts | null>(null)
|
|
1025
|
+
const [confirming, setConfirming] = useState(false)
|
|
1026
1026
|
|
|
1027
|
-
function
|
|
1027
|
+
function onConfirm(): void {
|
|
1028
1028
|
if (workspaceId === null) {
|
|
1029
1029
|
return
|
|
1030
1030
|
}
|
|
@@ -1033,6 +1033,7 @@ function SampleDataSection(): ReactNode {
|
|
|
1033
1033
|
.runAsync({ workspaceId })
|
|
1034
1034
|
.then((result) => {
|
|
1035
1035
|
setCounts(result)
|
|
1036
|
+
setConfirming(false)
|
|
1036
1037
|
})
|
|
1037
1038
|
.catch(() => undefined)
|
|
1038
1039
|
}
|
|
@@ -1044,32 +1045,73 @@ function SampleDataSection(): ReactNode {
|
|
|
1044
1045
|
<div>
|
|
1045
1046
|
<h2 className="text-[15px] font-semibold text-ink">Install sample data</h2>
|
|
1046
1047
|
<p className="mt-1 text-[13px] text-ink-muted">
|
|
1047
|
-
A small set of companies, people, and
|
|
1048
|
-
|
|
1048
|
+
A small set of companies, people, deals, and events so a workspace has something to look
|
|
1049
|
+
at. Existing records stay. This page asks before it writes.
|
|
1049
1050
|
</p>
|
|
1050
1051
|
</div>
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1052
|
+
{counts !== null ? (
|
|
1053
|
+
<button
|
|
1054
|
+
type="button"
|
|
1055
|
+
disabled
|
|
1056
|
+
className="rounded-md bg-accent px-3.5 py-2 text-[12px] font-semibold text-accent-fg opacity-50"
|
|
1057
|
+
>
|
|
1058
|
+
Installed
|
|
1059
|
+
</button>
|
|
1060
|
+
) : confirming ? (
|
|
1061
|
+
<div className="rounded-md border border-warning bg-warning-soft p-3 text-[13px] text-ink">
|
|
1062
|
+
<p>
|
|
1063
|
+
This adds sample companies, people, and other CRM records. Existing records are not
|
|
1064
|
+
removed. If sample emails or domains are already present, the install fails.
|
|
1065
|
+
</p>
|
|
1066
|
+
{failure === null ? null : (
|
|
1067
|
+
<p role="alert" className="mt-2 text-[12px] font-medium text-danger">
|
|
1068
|
+
{failure}
|
|
1069
|
+
</p>
|
|
1070
|
+
)}
|
|
1071
|
+
<div className="mt-2 flex justify-end gap-2">
|
|
1072
|
+
<button
|
|
1073
|
+
type="button"
|
|
1074
|
+
onClick={() => {
|
|
1075
|
+
setConfirming(false)
|
|
1076
|
+
}}
|
|
1077
|
+
disabled={install.isPending}
|
|
1078
|
+
className="rounded-md border border-border px-3 py-1 text-[12px] hover:bg-surface"
|
|
1079
|
+
>
|
|
1080
|
+
Cancel
|
|
1081
|
+
</button>
|
|
1082
|
+
<button
|
|
1083
|
+
type="button"
|
|
1084
|
+
onClick={onConfirm}
|
|
1085
|
+
disabled={install.isPending || workspaceId === null}
|
|
1086
|
+
className="rounded-md bg-accent px-3 py-1 text-[12px] font-semibold text-accent-fg hover:bg-accent-hover disabled:opacity-50"
|
|
1087
|
+
>
|
|
1088
|
+
{install.isPending ? 'Installing…' : 'Install sample data'}
|
|
1089
|
+
</button>
|
|
1090
|
+
</div>
|
|
1091
|
+
</div>
|
|
1092
|
+
) : (
|
|
1093
|
+
<button
|
|
1094
|
+
type="button"
|
|
1095
|
+
onClick={() => {
|
|
1096
|
+
setConfirming(true)
|
|
1097
|
+
}}
|
|
1098
|
+
disabled={workspaceId === null}
|
|
1099
|
+
className="rounded-md bg-accent px-3.5 py-2 text-[12px] font-semibold text-accent-fg transition hover:bg-accent-hover disabled:opacity-50"
|
|
1100
|
+
>
|
|
1101
|
+
Install sample data
|
|
1102
|
+
</button>
|
|
1103
|
+
)}
|
|
1063
1104
|
{counts !== null ? (
|
|
1064
1105
|
<p className="text-[12px] text-ink-muted">
|
|
1065
1106
|
Added {counts.companies} companies, {counts.people} people, {counts.positions}{' '}
|
|
1066
1107
|
positions, {counts.deals} deals, {counts.opportunities} opportunities,{' '}
|
|
1067
1108
|
{counts.raises} raises, {counts.partnerships} partnerships, {counts.enquiries}{' '}
|
|
1068
|
-
enquiries, {counts.roles} roles, {counts.candidates} candidates,{' '}
|
|
1069
|
-
{counts.planItems} plan items, and
|
|
1109
|
+
enquiries, {counts.roles} roles, {counts.candidates} candidates, {counts.events}{' '}
|
|
1110
|
+
events, {counts.attendances} attendances, {counts.planItems} plan items, and{' '}
|
|
1111
|
+
{counts.notes} notes.
|
|
1070
1112
|
</p>
|
|
1071
1113
|
) : null}
|
|
1072
|
-
{failure === null ? null : (
|
|
1114
|
+
{confirming || failure === null ? null : (
|
|
1073
1115
|
<p role="alert" className="text-[12px] font-medium text-danger">
|
|
1074
1116
|
{failure}
|
|
1075
1117
|
</p>
|
|
@@ -52,7 +52,7 @@ export function FieldsPage(): React.JSX.Element {
|
|
|
52
52
|
<div className="animate-slide-in mx-auto max-w-4xl space-y-6">
|
|
53
53
|
<PageHeader
|
|
54
54
|
title="Custom fields"
|
|
55
|
-
description="Add workspace-defined fields to
|
|
55
|
+
description="Add workspace-defined fields to People, Companies, pipeline records, and Events. Values on records go through the same API the UI uses."
|
|
56
56
|
/>
|
|
57
57
|
{isAdmin ? <FieldsAdmin /> : <MemberNotice />}
|
|
58
58
|
</div>
|
|
@@ -18,6 +18,7 @@ import { EntitySearch } from '../../components/EntitySearch.tsx'
|
|
|
18
18
|
import type { SearchOption } from '../../components/EntitySearch.tsx'
|
|
19
19
|
import { PageHeader } from '../../components/PageHeader.tsx'
|
|
20
20
|
import { ErrorPanel, LoadingPanel } from '../../components/QueryState.tsx'
|
|
21
|
+
import { TimezoneSearch } from '../../components/TimezoneSearch.tsx'
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* Workspace settings, and the one screen that can end a workspace.
|
|
@@ -32,22 +33,6 @@ import { ErrorPanel, LoadingPanel } from '../../components/QueryState.tsx'
|
|
|
32
33
|
* would be a stream of half-typed addresses.
|
|
33
34
|
*/
|
|
34
35
|
|
|
35
|
-
/**
|
|
36
|
-
* The timezones the mockup offered, plus whatever this workspace already holds.
|
|
37
|
-
*
|
|
38
|
-
* A full IANA list belongs in a combo box, which is its own piece of work. An
|
|
39
|
-
* unlisted value must still survive a save, so it joins the list rather than
|
|
40
|
-
* being silently rewritten to the first option.
|
|
41
|
-
*/
|
|
42
|
-
const COMMON_TIMEZONES = [
|
|
43
|
-
'Australia/Sydney',
|
|
44
|
-
'Australia/Melbourne',
|
|
45
|
-
'America/Los_Angeles',
|
|
46
|
-
'America/New_York',
|
|
47
|
-
'Europe/London',
|
|
48
|
-
'UTC',
|
|
49
|
-
] as const
|
|
50
|
-
|
|
51
36
|
export function WorkspaceSettingsPage(): React.JSX.Element {
|
|
52
37
|
const { workspace, isLoading, error } = useWorkspace()
|
|
53
38
|
|
|
@@ -77,9 +62,6 @@ function WorkspaceSettingsForm({
|
|
|
77
62
|
const [saved, setSaved] = useState(false)
|
|
78
63
|
|
|
79
64
|
const canEdit = session?.role === 'owner' || session?.role === 'admin'
|
|
80
|
-
const timezones = COMMON_TIMEZONES.includes(timezone as (typeof COMMON_TIMEZONES)[number])
|
|
81
|
-
? [...COMMON_TIMEZONES]
|
|
82
|
-
: [timezone, ...COMMON_TIMEZONES]
|
|
83
65
|
|
|
84
66
|
function save(event: FormEvent): void {
|
|
85
67
|
event.preventDefault()
|
|
@@ -130,20 +112,15 @@ function WorkspaceSettingsForm({
|
|
|
130
112
|
</Field>
|
|
131
113
|
|
|
132
114
|
<Field label="Timezone">
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
setTimezone
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
<option key={zone} value={zone}>
|
|
143
|
-
{zone}
|
|
144
|
-
</option>
|
|
145
|
-
))}
|
|
146
|
-
</select>
|
|
115
|
+
<div className="max-w-md">
|
|
116
|
+
<TimezoneSearch
|
|
117
|
+
value={timezone}
|
|
118
|
+
onChange={setTimezone}
|
|
119
|
+
required
|
|
120
|
+
disabled={!canEdit}
|
|
121
|
+
size="md"
|
|
122
|
+
/>
|
|
123
|
+
</div>
|
|
147
124
|
</Field>
|
|
148
125
|
|
|
149
126
|
{update.error !== null && (
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
2
|
import { Link } from 'react-router'
|
|
3
3
|
|
|
4
|
+
import { RegionSwitcher } from './RegionSwitcher.tsx'
|
|
5
|
+
|
|
4
6
|
/**
|
|
5
7
|
* The centred card every signed-out page sits in: sign in, signup, the two
|
|
6
|
-
* password-reset pages, and the
|
|
8
|
+
* password-reset pages, and the five onboarding steps.
|
|
7
9
|
*
|
|
8
10
|
* `step` is what makes it an onboarding page. Onboarding is a sequence somebody
|
|
9
11
|
* is part-way through, and a card that does not say where they are in it turns
|
|
10
|
-
*
|
|
12
|
+
* five screens into five unrelated forms. The region switcher stays off
|
|
13
|
+
* those steps: a session already exists on this origin.
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
|
-
/** Onboarding, per `onboarding.md`: workspace, invites, handbook. */
|
|
14
|
-
const ONBOARDING_STEPS = [1, 2, 3] as const
|
|
16
|
+
/** Onboarding, per `onboarding.md`: workspace, organisation, modules, invites, handbook. */
|
|
17
|
+
const ONBOARDING_STEPS = [1, 2, 3, 4, 5] as const
|
|
15
18
|
|
|
16
19
|
export type OnboardingStep = (typeof ONBOARDING_STEPS)[number]
|
|
17
20
|
|
|
@@ -50,6 +53,7 @@ export function AuthLayout({
|
|
|
50
53
|
{children}
|
|
51
54
|
{footer !== undefined && <div className="mt-4 text-center text-[12px]">{footer}</div>}
|
|
52
55
|
</div>
|
|
56
|
+
{step === undefined && <RegionSwitcher />}
|
|
53
57
|
</div>
|
|
54
58
|
)
|
|
55
59
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ChangeEvent } from 'react'
|
|
2
|
+
|
|
3
|
+
import { usePublicConfig } from '../../api/resources/publicConfig.ts'
|
|
4
|
+
import { regionHref } from './regionHref.ts'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A region picker for signed-out pages.
|
|
8
|
+
*
|
|
9
|
+
* Hidden unless public config lists two or more origins. Selecting another
|
|
10
|
+
* region leaves this origin: the session cookie is host-scoped, so the
|
|
11
|
+
* browser has to load the other host's login page. Path, query, and hash
|
|
12
|
+
* stay, so `/login?next=` and invite tokens survive the hop.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
export function RegionSwitcher(): React.JSX.Element | null {
|
|
16
|
+
const { config } = usePublicConfig()
|
|
17
|
+
const regions = config?.regions ?? []
|
|
18
|
+
|
|
19
|
+
if (regions.length < 2) {
|
|
20
|
+
return null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const current = regions.find((region) => region.origin === window.location.origin)
|
|
24
|
+
|
|
25
|
+
function change(event: ChangeEvent<HTMLSelectElement>): void {
|
|
26
|
+
const selected = regions.find((region) => region.id === event.target.value)
|
|
27
|
+
|
|
28
|
+
if (selected === undefined || selected.origin === window.location.origin) {
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
window.location.assign(regionHref(selected.origin, window.location))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<label className="mt-6 block w-full max-w-sm">
|
|
37
|
+
<span className="mb-1.5 block text-[12px] font-medium text-ink">Region</span>
|
|
38
|
+
<select
|
|
39
|
+
className="w-full rounded-md border border-border bg-transparent px-2 py-1 text-[13px] outline-none focus:border-accent"
|
|
40
|
+
value={current?.id ?? ''}
|
|
41
|
+
onChange={change}
|
|
42
|
+
>
|
|
43
|
+
{current === undefined && (
|
|
44
|
+
<option value="" disabled>
|
|
45
|
+
Select a region
|
|
46
|
+
</option>
|
|
47
|
+
)}
|
|
48
|
+
{regions.map((region) => (
|
|
49
|
+
<option key={region.id} value={region.id}>
|
|
50
|
+
{region.label}
|
|
51
|
+
</option>
|
|
52
|
+
))}
|
|
53
|
+
</select>
|
|
54
|
+
</label>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
@@ -2,6 +2,7 @@ import { useState } from 'react'
|
|
|
2
2
|
import type { FormEvent } from 'react'
|
|
3
3
|
import { Link, useNavigate, useSearchParams } from 'react-router'
|
|
4
4
|
|
|
5
|
+
import { usePublicConfig } from '../../api/resources/publicConfig.ts'
|
|
5
6
|
import { useLogIn } from '../../api/resources/session.ts'
|
|
6
7
|
import { ErrorPanel } from '../../components/QueryState.tsx'
|
|
7
8
|
import { SubmitButton, TextField } from './AuthForm.tsx'
|
|
@@ -21,6 +22,7 @@ export function SignInPage(): React.JSX.Element {
|
|
|
21
22
|
const navigate = useNavigate()
|
|
22
23
|
const [searchParameters] = useSearchParams()
|
|
23
24
|
const logIn = useLogIn()
|
|
25
|
+
const { config } = usePublicConfig()
|
|
24
26
|
const [email, setEmail] = useState('')
|
|
25
27
|
const [password, setPassword] = useState('')
|
|
26
28
|
|
|
@@ -43,12 +45,14 @@ export function SignInPage(): React.JSX.Element {
|
|
|
43
45
|
<Link to="/forgot-password" className="font-medium text-accent hover:underline">
|
|
44
46
|
Forgot password?
|
|
45
47
|
</Link>
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
{config?.signupsEnabled !== false && (
|
|
49
|
+
<span className="text-ink-muted">
|
|
50
|
+
No account?{' '}
|
|
51
|
+
<Link to="/signup" className="font-medium text-accent hover:underline">
|
|
52
|
+
Sign up
|
|
53
|
+
</Link>
|
|
54
|
+
</span>
|
|
55
|
+
)}
|
|
52
56
|
</div>
|
|
53
57
|
}
|
|
54
58
|
>
|
|
@@ -3,6 +3,7 @@ import { useState } from 'react'
|
|
|
3
3
|
import type { FormEvent } from 'react'
|
|
4
4
|
import { Link, useNavigate } from 'react-router'
|
|
5
5
|
|
|
6
|
+
import { usePublicConfig } from '../../api/resources/publicConfig.ts'
|
|
6
7
|
import { useSignUp } from '../../api/resources/session.ts'
|
|
7
8
|
import { ErrorPanel } from '../../components/QueryState.tsx'
|
|
8
9
|
import { SubmitButton, TextField } from './AuthForm.tsx'
|
|
@@ -25,11 +26,35 @@ import { AuthMethods } from './AuthMethods.tsx'
|
|
|
25
26
|
export function SignUpPage(): React.JSX.Element {
|
|
26
27
|
const navigate = useNavigate()
|
|
27
28
|
const signUp = useSignUp()
|
|
29
|
+
const { config } = usePublicConfig()
|
|
28
30
|
const [name, setName] = useState('')
|
|
29
31
|
const [email, setEmail] = useState('')
|
|
30
32
|
const [password, setPassword] = useState('')
|
|
31
33
|
const [localError, setLocalError] = useState<string | null>(null)
|
|
32
34
|
|
|
35
|
+
// Undefined (still loading) renders the form, same as the server's own
|
|
36
|
+
// default: a caller that has not thought about it sees no change.
|
|
37
|
+
if (config?.signupsEnabled === false) {
|
|
38
|
+
return (
|
|
39
|
+
<AuthLayout
|
|
40
|
+
title="Signups are closed"
|
|
41
|
+
footer={
|
|
42
|
+
<span className="text-ink-muted">
|
|
43
|
+
Already have an account?{' '}
|
|
44
|
+
<Link to="/login" className="font-medium text-accent hover:underline">
|
|
45
|
+
Sign in
|
|
46
|
+
</Link>
|
|
47
|
+
</span>
|
|
48
|
+
}
|
|
49
|
+
>
|
|
50
|
+
<p className="mt-5 text-ink-muted">
|
|
51
|
+
This instance is not accepting new accounts right now. If you were invited to a
|
|
52
|
+
workspace, use the link from your invitation email instead.
|
|
53
|
+
</p>
|
|
54
|
+
</AuthLayout>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
33
58
|
function submit(event: FormEvent): void {
|
|
34
59
|
event.preventDefault()
|
|
35
60
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The URL a region switcher navigates to: the other origin, plus the path,
|
|
3
|
+
* query, and hash the reader is already on.
|
|
4
|
+
*/
|
|
5
|
+
export function regionHref(
|
|
6
|
+
origin: string,
|
|
7
|
+
location: Pick<Location, 'pathname' | 'search' | 'hash'>,
|
|
8
|
+
): string {
|
|
9
|
+
return `${origin}${location.pathname}${location.search}${location.hash}`
|
|
10
|
+
}
|
|
@@ -7,7 +7,7 @@ import { useWorkspace } from '../../api/resources/workspace.ts'
|
|
|
7
7
|
import { AgentTasks } from '../../components/AgentTasks.tsx'
|
|
8
8
|
import { PageHeader } from '../../components/PageHeader.tsx'
|
|
9
9
|
import { ErrorPanel, LoadingPanel } from '../../components/QueryState.tsx'
|
|
10
|
-
import { attentionRows
|
|
10
|
+
import { attentionRows } from './attention.ts'
|
|
11
11
|
import { ActivityFeed, AttentionList, DecisionsList, NotesList } from './sections.tsx'
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -19,37 +19,34 @@ import { ActivityFeed, AttentionList, DecisionsList, NotesList } from './section
|
|
|
19
19
|
* for its name, and the team, to turn an author id into a person.
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
/** The heading date, written in the workspace's own day rather than the browser's. */
|
|
23
|
-
function briefHeading(dashboard: Dashboard): string {
|
|
24
|
-
return new Intl.DateTimeFormat(undefined, {
|
|
25
|
-
weekday: 'long',
|
|
26
|
-
month: 'short',
|
|
27
|
-
day: 'numeric',
|
|
28
|
-
timeZone: dashboard.timezone,
|
|
29
|
-
}).format(dashboard.generatedAt)
|
|
30
|
-
}
|
|
31
|
-
|
|
32
22
|
export function DashboardPage(): React.JSX.Element {
|
|
33
23
|
const { dashboard, isLoading, error } = useDashboard()
|
|
34
24
|
const { workspace } = useWorkspace()
|
|
35
25
|
const { nameById } = useMembers()
|
|
36
26
|
const timezone = useTimezone()
|
|
27
|
+
const workspaceName = workspace?.name ?? 'This workspace'
|
|
37
28
|
|
|
38
29
|
return (
|
|
39
30
|
<div className="animate-fade-in">
|
|
40
|
-
<PageHeader
|
|
31
|
+
<PageHeader
|
|
32
|
+
title="Dashboard"
|
|
33
|
+
description="What needs attention across this workspace."
|
|
34
|
+
actions={
|
|
35
|
+
workspace?.id !== undefined ? (
|
|
36
|
+
<AgentTasks
|
|
37
|
+
targetType="workspace"
|
|
38
|
+
targetId={workspace.id}
|
|
39
|
+
targetLabel={workspaceName}
|
|
40
|
+
/>
|
|
41
|
+
) : undefined
|
|
42
|
+
}
|
|
43
|
+
/>
|
|
41
44
|
|
|
42
45
|
{error !== null && <ErrorPanel error={error} />}
|
|
43
46
|
{isLoading && <LoadingPanel label="Loading the workspace…" />}
|
|
44
47
|
|
|
45
48
|
{dashboard !== undefined && (
|
|
46
|
-
<DashboardBody
|
|
47
|
-
dashboard={dashboard}
|
|
48
|
-
workspaceId={workspace?.id}
|
|
49
|
-
workspaceName={workspace?.name ?? 'This workspace'}
|
|
50
|
-
nameById={nameById}
|
|
51
|
-
timezone={timezone}
|
|
52
|
-
/>
|
|
49
|
+
<DashboardBody dashboard={dashboard} nameById={nameById} timezone={timezone} />
|
|
53
50
|
)}
|
|
54
51
|
</div>
|
|
55
52
|
)
|
|
@@ -57,14 +54,10 @@ export function DashboardPage(): React.JSX.Element {
|
|
|
57
54
|
|
|
58
55
|
function DashboardBody({
|
|
59
56
|
dashboard,
|
|
60
|
-
workspaceId,
|
|
61
|
-
workspaceName,
|
|
62
57
|
nameById,
|
|
63
58
|
timezone,
|
|
64
59
|
}: {
|
|
65
60
|
readonly dashboard: Dashboard
|
|
66
|
-
readonly workspaceId: string | undefined
|
|
67
|
-
readonly workspaceName: string
|
|
68
61
|
readonly nameById: ReadonlyMap<string, string>
|
|
69
62
|
readonly timezone: string
|
|
70
63
|
}): React.JSX.Element {
|
|
@@ -75,31 +68,6 @@ function DashboardBody({
|
|
|
75
68
|
|
|
76
69
|
return (
|
|
77
70
|
<div>
|
|
78
|
-
<section className="mb-8 border-b border-border pb-6">
|
|
79
|
-
<div className="flex flex-wrap items-start justify-between gap-3">
|
|
80
|
-
<div>
|
|
81
|
-
<p className="text-[11px] text-ink-faint">Daily brief</p>
|
|
82
|
-
<h2 className="mt-0.5 text-[15px] font-semibold tracking-tight text-ink">
|
|
83
|
-
{workspaceName} · {briefHeading(dashboard)}
|
|
84
|
-
</h2>
|
|
85
|
-
<p className="mt-1 text-[12px] text-ink-muted">
|
|
86
|
-
Assembled from overdue Plans, partnership touchpoints, and contacts going cold.
|
|
87
|
-
</p>
|
|
88
|
-
</div>
|
|
89
|
-
{workspaceId !== undefined && (
|
|
90
|
-
<AgentTasks targetType="workspace" targetId={workspaceId} targetLabel={workspaceName} />
|
|
91
|
-
)}
|
|
92
|
-
</div>
|
|
93
|
-
<ul className="mt-4 space-y-1.5">
|
|
94
|
-
{briefLines(dashboard).map((line) => (
|
|
95
|
-
<li key={line} className="flex gap-2 text-[13px] leading-relaxed text-ink">
|
|
96
|
-
<span className="mt-[9px] h-1 w-1 shrink-0 rounded-full bg-accent" />
|
|
97
|
-
<span>{line}</span>
|
|
98
|
-
</li>
|
|
99
|
-
))}
|
|
100
|
-
</ul>
|
|
101
|
-
</section>
|
|
102
|
-
|
|
103
71
|
<div className="mb-8 grid gap-8 lg:grid-cols-2">
|
|
104
72
|
<AttentionList rows={attentionRows(dashboard)} />
|
|
105
73
|
<ActivityFeed
|