mirror of
https://github.com/Crosstalk-Solutions/project-nomad.git
synced 2026-04-09 18:26:15 +02:00
feat: easy setup wizard
This commit is contained in:
parent
6500599c6d
commit
4b74118fd9
|
|
@ -27,7 +27,7 @@ const InstallActivityFeed: React.FC<InstallActivityFeedProps> = ({ activity, cla
|
||||||
return (
|
return (
|
||||||
<div className={classNames('bg-white shadow-sm rounded-lg p-6', className)}>
|
<div className={classNames('bg-white shadow-sm rounded-lg p-6', className)}>
|
||||||
{withHeader && <h2 className="text-lg font-semibold text-gray-900">Installation Activity</h2>}
|
{withHeader && <h2 className="text-lg font-semibold text-gray-900">Installation Activity</h2>}
|
||||||
<ul role="list" className="mt-6 space-y-6 text-desert-green">
|
<ul role="list" className={classNames("space-y-6 text-desert-green", withHeader ? 'mt-6' : '')}>
|
||||||
{activity.map((activityItem, activityItemIdx) => (
|
{activity.map((activityItem, activityItemIdx) => (
|
||||||
<li key={activityItem.timestamp} className="relative flex gap-x-4">
|
<li key={activityItem.timestamp} className="relative flex gap-x-4">
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { useEffect, useState } from 'react';
|
||||||
import api from '~/lib/api';
|
import api from '~/lib/api';
|
||||||
|
|
||||||
const useInternetStatus = () => {
|
const useInternetStatus = () => {
|
||||||
const [isOnline, setIsOnline] = useState<boolean>(false);
|
const [isOnline, setIsOnline] = useState<boolean>(true); // Initialize true to avoid "offline" flicker on load
|
||||||
const { data } = useQuery<boolean>({
|
const { data } = useQuery<boolean>({
|
||||||
queryKey: ['internetStatus'],
|
queryKey: ['internetStatus'],
|
||||||
queryFn: async () => (await api.getInternetStatus()) ?? false,
|
queryFn: async () => (await api.getInternetStatus()) ?? false,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Head, router } from '@inertiajs/react'
|
import { Head, router } from '@inertiajs/react'
|
||||||
import { useQuery } from '@tanstack/react-query'
|
import { useQuery } from '@tanstack/react-query'
|
||||||
import { useState, useMemo } from 'react'
|
import { useState } from 'react'
|
||||||
import AppLayout from '~/layouts/AppLayout'
|
import AppLayout from '~/layouts/AppLayout'
|
||||||
import StyledButton from '~/components/StyledButton'
|
import StyledButton from '~/components/StyledButton'
|
||||||
import api from '~/lib/api'
|
import api from '~/lib/api'
|
||||||
|
|
@ -42,9 +42,9 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
const availableServices = useMemo(() => {
|
const availableServices = props.system.services.filter(
|
||||||
return props.system.services.filter((service) => !service.installed)
|
(service) => !service.installed && service.installation_status !== 'installing'
|
||||||
}, [props.system.services])
|
)
|
||||||
|
|
||||||
const toggleServiceSelection = (serviceName: string) => {
|
const toggleServiceSelection = (serviceName: string) => {
|
||||||
setSelectedServices((prev) =>
|
setSelectedServices((prev) =>
|
||||||
|
|
@ -97,26 +97,23 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// All of these ops don't actually wait for completion, they just kick off the process, so we can run them in parallel without awaiting each one sequentially
|
// All of these ops don't actually wait for completion, they just kick off the process, so we can run them in parallel without awaiting each one sequentially
|
||||||
// const installPromises = selectedServices.map((serviceName) => api.installService(serviceName))
|
const installPromises = selectedServices.map((serviceName) => api.installService(serviceName))
|
||||||
|
|
||||||
// await Promise.all(installPromises)
|
await Promise.all(installPromises)
|
||||||
|
|
||||||
// const downloadPromises = [
|
const downloadPromises = [
|
||||||
// ...selectedMapCollections.map((slug) => api.downloadMapCollection(slug)),
|
...selectedMapCollections.map((slug) => api.downloadMapCollection(slug)),
|
||||||
// ...selectedZimCollections.map((slug) => api.downloadZimCollection(slug)),
|
...selectedZimCollections.map((slug) => api.downloadZimCollection(slug)),
|
||||||
// ]
|
]
|
||||||
|
|
||||||
// await Promise.all(downloadPromises)
|
await Promise.all(downloadPromises)
|
||||||
|
|
||||||
addNotification({
|
addNotification({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: 'Setup wizard completed! Your selections are being processed.',
|
message: 'Setup wizard completed! Your selections are being processed.',
|
||||||
})
|
})
|
||||||
|
|
||||||
// Wait a moment then redirect to completion page to show progress
|
router.visit('/easy-setup/complete')
|
||||||
setTimeout(() => {
|
|
||||||
router.visit('/easy-setup/complete')
|
|
||||||
}, 2000)
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error during setup:', error)
|
console.error('Error during setup:', error)
|
||||||
addNotification({
|
addNotification({
|
||||||
|
|
@ -226,26 +223,17 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||||
{availableServices.map((service) => {
|
{availableServices.map((service) => {
|
||||||
const selectedOrInstalled =
|
const selected = selectedServices.includes(service.service_name)
|
||||||
selectedServices.includes(service.service_name) ||
|
|
||||||
service.installed ||
|
|
||||||
service.installation_status === 'installing'
|
|
||||||
|
|
||||||
const installedOrInstalling =
|
|
||||||
service.installed || service.installation_status === 'installing'
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={service.id}
|
key={service.id}
|
||||||
onClick={() =>
|
onClick={() => toggleServiceSelection(service.service_name)}
|
||||||
!installedOrInstalling && toggleServiceSelection(service.service_name)
|
|
||||||
}
|
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'p-6 rounded-lg border-2 cursor-pointer transition-all',
|
'p-6 rounded-lg border-2 cursor-pointer transition-all',
|
||||||
selectedOrInstalled
|
selected
|
||||||
? 'border-desert-green bg-desert-green bg-opacity-10 shadow-md text-white'
|
? 'border-desert-green bg-desert-green bg-opacity-10 shadow-md text-white'
|
||||||
: 'border-desert-stone-light bg-white hover:border-desert-green hover:shadow-sm',
|
: 'border-desert-stone-light bg-white hover:border-desert-green hover:shadow-sm'
|
||||||
installedOrInstalling ? 'opacity-50 cursor-not-allowed' : ''
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start justify-between">
|
<div className="flex items-start justify-between">
|
||||||
|
|
@ -256,7 +244,7 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
<p
|
<p
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'text-sm mt-1',
|
'text-sm mt-1',
|
||||||
selectedOrInstalled ? 'text-white' : 'text-gray-600'
|
selected ? 'text-white' : 'text-gray-600'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{service.description}
|
{service.description}
|
||||||
|
|
@ -265,12 +253,10 @@ export default function EasySetupWizard(props: { system: { services: ServiceSlim
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'ml-4 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all',
|
'ml-4 w-6 h-6 rounded-full border-2 flex items-center justify-center transition-all',
|
||||||
selectedOrInstalled
|
selected ? 'border-desert-green bg-desert-green' : 'border-desert-stone'
|
||||||
? 'border-desert-green bg-desert-green'
|
|
||||||
: 'border-desert-stone'
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{selectedOrInstalled ? (
|
{selected ? (
|
||||||
<IconCheck size={20} className="text-white" />
|
<IconCheck size={20} className="text-white" />
|
||||||
) : (
|
) : (
|
||||||
<div className="w-5 h-5 rounded-full bg-transparent" />
|
<div className="w-5 h-5 rounded-full bg-transparent" />
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,7 @@ export default function ZimRemoteExplorer() {
|
||||||
key={collection.slug}
|
key={collection.slug}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
onClick={(collection) => confirmDownload(collection)}
|
onClick={(collection) => confirmDownload(collection)}
|
||||||
|
size='large'
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user