-
Notifications
You must be signed in to change notification settings - Fork 11.7k
Description
RFC summary of the recent discussion around apps (previously integrations) and what the best architecture is to build third-party apps
Goals
- super easy to launch your own app
- unified abstractions around installation, removal, authentication (i.e. OAuth)
- minimize merge conflicts
- touch as little lines of
core codeas possible (with smart abstractions)
Status quo
- the new app store branch is introducing a new folder
appswhere each new app can live in (i.e.apps/zoom) with metadata, images, descriptions, etc., however, it is not clear yet how the zoom app will be hooked into the core app. - right now, apps like "web3" are hardcoded into event-types and booking pages
Proposal
What if we find a good abstraction (like WordPress, i know–different set of technologies) that allows adding apps to the core views without touching them.
Example 1:
in Shell.tsx
cal.com/apps/web/components/Shell.tsx
Line 138 in 8996c16
| const navigation = [ |
we have
const navigation = [
{
name: t("event_types_page_title"),
href: "/event-types",
icon: LinkIcon,
current: router.asPath.startsWith("/event-types"),
},
{
name: t("bookings"),
href: "/bookings/upcoming",
icon: CalendarIcon,
current: router.asPath.startsWith("/bookings"),
},
{
name: t("availability"),
href: "/availability",
icon: ClockIcon,
current: router.asPath.startsWith("/availability"),
},
{
name: t("integrations"),
href: "/integrations",
icon: PuzzleIcon,
current: router.asPath.startsWith("/integrations"),
},
{
name: t("settings"),
href: "/settings/profile",
icon: CogIcon,
current: router.asPath.startsWith("/settings"),
},
];
what if we extend this
<nav className="mt-2 flex-1 space-y-1 bg-white px-2 lg:mt-5">
{navigation.map((item) => (
<Link key={item.name} href={item.href}>
<a
className={classNames(
item.current
? "bg-neutral-100 text-neutral-900"
: "text-neutral-500 hover:bg-gray-50 hover:text-neutral-900",
"group flex items-center rounded-sm px-2 py-2 text-sm font-medium"
)}>
<item.icon
className={classNames(
item.current
? "text-neutral-500"
: "text-neutral-400 group-hover:text-neutral-500",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
<span className="hidden lg:inline">{item.name}</span>
</a>
</Link>
))}
</nav>
with appNavigation:
<nav className="mt-2 flex-1 space-y-1 bg-white px-2 lg:mt-5">
{navigation.map((item) => (
<Link key={item.name} href={item.href}>
<a
className={classNames(
item.current
? "bg-neutral-100 text-neutral-900"
: "text-neutral-500 hover:bg-gray-50 hover:text-neutral-900",
"group flex items-center rounded-sm px-2 py-2 text-sm font-medium"
)}>
<item.icon
className={classNames(
item.current
? "text-neutral-500"
: "text-neutral-400 group-hover:text-neutral-500",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
<span className="hidden lg:inline">{item.name}</span>
</a>
</Link>
))}
<hr/>
{appNavigation.map((item) => (
<Link key={item.name} href={item.href}>
<a
className={classNames(
item.current
? "bg-neutral-100 text-neutral-900"
: "text-neutral-500 hover:bg-gray-50 hover:text-neutral-900",
"group flex items-center rounded-sm px-2 py-2 text-sm font-medium"
)}>
<item.icon
className={classNames(
item.current
? "text-neutral-500"
: "text-neutral-400 group-hover:text-neutral-500",
"h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3"
)}
aria-hidden="true"
/>
<span className="hidden lg:inline">{item.name}</span>
</a>
</Link>
))}
</nav>
and appNavigation is dynamically built based on either file-system or other references in apps/appRegistry.ts
Goal: don't touch navigation when adding a new app (note: not every apps needs a navigation item)
Example 2:
event-types/[type].tsx
cal.com/apps/web/pages/event-types/[type].tsx
Line 419 in 8996c16
| {location.type === LocationType.GoogleMeet && ( |
should abstract all video apps and not hardcode them into the page
Goal: don't touch this file when adding a new video app (less merge conflicts, less redundant code)
Example 3:
DRAFT: Calendar Integrations