Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 102 additions & 0 deletions ui/src/modules/common/components/EmptyState.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { PlayCircle, Plus, GitCommit } from "@phosphor-icons/react"
import { Button } from "antd"
import { EmptyStateType, EmptyStateConfig } from "../../../utils/constants"

interface EmptyStateProps {
type: EmptyStateType
onButtonClick: () => void
}

interface TutorialCardProps {
tutorial: {
link: string
image: string
}
type: string
}

const TutorialCard = ({ tutorial, type }: TutorialCardProps) => (
<div className="w-[412px] rounded-xl border border-neutral-disabled bg-white p-4 shadow-sm">
<div className="flex items-center gap-4">
<a
href={tutorial.link}
target="_blank"
rel="noopener noreferrer"
className="cursor-pointer"
>
<img
src={tutorial.image}
alt={`${type} tutorial`}
className="rounded-lg transition-opacity hover:opacity-80"
/>
</a>
<div className="flex-1">
<div className="mb-1 flex items-center gap-1 text-xs">
<PlayCircle className="text-text-placeholder" />
<span className="text-text-placeholder">OLake / Tutorial</span>
</div>
<div className="text-xs">
Checkout this tutorial to know more about {type.toLowerCase()}
</div>
</div>
</div>
</div>
)

const getButtonClass = (type: EmptyStateType) =>
type === EmptyStateType.JOB
? "border-brand-blue bg-brand-blue text-white"
: "border-neutral-disabled bg-white text-black"

const getEmptyStateMessage = (type: EmptyStateType, config: any) => {
switch (type) {
case EmptyStateType.SOURCE:
return "Ready to create your first source"
case EmptyStateType.DESTINATION:
return "Ready to create your first destination"
case EmptyStateType.JOB:
return "Ready to run your first Job"
default:
return `Ready to run your first ${config.title}`
}
}

const EmptyState = ({ type, onButtonClick }: EmptyStateProps) => {
const config = EmptyStateConfig[type]
if (!config) return null

return (
<div className="flex flex-col items-center justify-center py-16">
<img
src={config.image}
alt={`${type} empty state illustration`}
className="mb-8 h-64 w-96"
/>
<div className="mb-2 font-medium text-brand-blue">Welcome User !</div>
<h2 className="mb-2 text-2xl font-bold">
{getEmptyStateMessage(type, config)}
</h2>
<p className="mb-8 text-text-primary">
Get started and experience the speed of{" "}
<span className="font-bold">OLake</span> by setting up
{config.description}
</p>
<Button
type="primary"
className={`mb-12 px-6 py-4 ${getButtonClass(type)}`}
onClick={onButtonClick}
>
{type === EmptyStateType.JOB ? <GitCommit /> : <Plus />}
{config.buttonText}
</Button>
{config.tutorial && (
<TutorialCard
tutorial={config.tutorial}
type={type}
/>
)}
</div>
)
}

export default EmptyState
64 changes: 0 additions & 64 deletions ui/src/modules/destinations/components/DestinationEmptyState.tsx

This file was deleted.

10 changes: 6 additions & 4 deletions ui/src/modules/destinations/pages/Destinations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import { Button, Tabs, Empty, message, Spin } from "antd"
import analyticsService from "../../../api/services/analyticsService"
import { useAppStore } from "../../../store"
import { Entity } from "../../../types"
import { destinationTabs } from "../../../utils/constants"
import DestinationEmptyState from "../components/DestinationEmptyState"

import { destinationTabs, EmptyStateType } from "../../../utils/constants"
import EmptyState from "../../common/components/EmptyState"
import DestinationTable from "../components/DestinationTable"

const Destinations: React.FC = () => {
Expand Down Expand Up @@ -128,8 +129,9 @@ const Destinations: React.FC = () => {
/>
</div>
) : tab.key === "active" && showEmpty ? (
<DestinationEmptyState
handleCreateDestination={handleCreateDestination}
<EmptyState
type={EmptyStateType.DESTINATION}
onButtonClick={handleCreateDestination}
/>
) : filteredDestinations().length === 0 ? (
<Empty
Expand Down
62 changes: 0 additions & 62 deletions ui/src/modules/jobs/components/JobEmptyState.tsx

This file was deleted.

9 changes: 6 additions & 3 deletions ui/src/modules/jobs/pages/Jobs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { useState, useEffect } from "react"
import { useNavigate } from "react-router-dom"
import { Button, Tabs, Empty, message, Spin } from "antd"
import { GitCommit, Plus } from "@phosphor-icons/react"

import { EmptyStateType } from "../../../utils/constants"
import { useAppStore } from "../../../store"
import { jobService } from "../../../api"
import analyticsService from "../../../api/services/analyticsService"
import { JobType } from "../../../types/jobTypes"
import { JOB_TYPES } from "../../../utils/constants"
import JobTable from "../components/JobTable"
import JobEmptyState from "../components/JobEmptyState"
import EmptyState from "../../common/components/EmptyState"
import DeleteJobModal from "../../common/Modals/DeleteJobModal"

const Jobs: React.FC = () => {
Expand Down Expand Up @@ -197,7 +197,10 @@ const Jobs: React.FC = () => {
/>
</div>
) : tab.key === JOB_TYPES.ACTIVE && showEmpty ? (
<JobEmptyState handleCreateJob={handleCreateJob} />
<EmptyState
type={EmptyStateType.JOB}
onButtonClick={handleCreateJob}
/>
) : filteredJobs.length === 0 ? (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
Expand Down
64 changes: 0 additions & 64 deletions ui/src/modules/sources/components/SourceEmptyState.tsx

This file was deleted.

10 changes: 6 additions & 4 deletions ui/src/modules/sources/pages/Sources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import { useState, useEffect } from "react"
import { useNavigate } from "react-router-dom"
import { Button, Tabs, Empty, message, Spin } from "antd"
import { LinktreeLogo, Plus } from "@phosphor-icons/react"

import EmptyState from "../../common/components/EmptyState"
import { useAppStore } from "../../../store"
import analyticsService from "../../../api/services/analyticsService"
import { Entity } from "../../../types"
import { sourceTabs } from "../../../utils/constants"
import { EmptyStateType, sourceTabs } from "../../../utils/constants"
import SourceTable from "../components/SourceTable"
import SourceEmptyState from "../components/SourceEmptyState"

const Sources: React.FC = () => {
const [activeTab, setActiveTab] = useState("active")
Expand Down Expand Up @@ -130,7 +129,10 @@ const Sources: React.FC = () => {
/>
</div>
) : tab.key === "active" && showEmpty ? (
<SourceEmptyState handleCreateSource={handleCreateSource} />
<EmptyState
type={EmptyStateType.SOURCE}
onButtonClick={handleCreateSource}
/>
) : filteredSources().length === 0 ? (
<Empty
image={Empty.PRESENTED_IMAGE_SIMPLE}
Expand Down
Loading