File size: 4,521 Bytes
6a7089a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import { useState, useEffect, useCallback } from "react";
import InstanceLogsPanel from "./InstanceLogsPanel";
import ProfileMetaInfoPanel from "./ProfileMetaInfoPanel";
import ProfileBasicInfoPanel from "./ProfileBasicInfoPanel";
import ProfileLiveViewPanel from "./ProfileLiveViewPanel";
import ProfileToolbar from "./ProfileToolbar";
import { InstanceTabsPanel } from "../tabs";
import { TabsLayout, EmptyView } from "../molecules";
import type { Profile, Instance, InstanceTab } from "../../generated/types";
import * as api from "../../services/api";

interface Props {
  profile: Profile | null;
  instance?: Instance;
  onLaunch: () => void;
  onStop?: () => void;
  onSave?: (name: string, useWhen: string) => void;
  onDelete?: () => void;
}

type TabId = "profile" | "live" | "tabs" | "logs";

export default function ProfileDetailsPanel({
  profile,
  instance,
  onLaunch,
  onStop,
  onSave,
  onDelete,
}: Props) {
  const [activeTab, setActiveTab] = useState<TabId>("profile");
  const [tabs, setTabs] = useState<InstanceTab[]>([]);
  const [formValues, setFormValues] = useState({ name: "", useWhen: "" });

  const isRunning = instance?.status === "running";

  useEffect(() => {
    if (profile) {
      setFormValues({ name: profile.name, useWhen: profile.useWhen || "" });
    } else {
      setTabs([]);
      setFormValues({ name: "", useWhen: "" });
    }
  }, [profile]);

  const handleProfileChange = useCallback((name: string, useWhen: string) => {
    setFormValues({ name, useWhen });
  }, []);

  const loadTabs = useCallback(async () => {
    if (!instance?.id) {
      setTabs([]);
      return;
    }

    try {
      const instanceTabs = await api
        .fetchInstanceTabs(instance.id)
        .catch(() => []);
      setTabs(instanceTabs);
    } catch (e) {
      console.error("Failed to load tabs", e);
    }
  }, [instance]);

  useEffect(() => {
    if (activeTab === "live" || activeTab === "tabs" || activeTab === "logs") {
      loadTabs();
    }
  }, [activeTab, loadTabs]);

  const handleSave = () => {
    onSave?.(formValues.name, formValues.useWhen);
  };

  if (!profile) {
    return (
      <div className="dashboard-panel h-full min-h-112">
        <EmptyView message="Select a profile to inspect its instance, live tabs, and logs." />
      </div>
    );
  }

  const hasChanges =
    formValues.name.trim() !== profile.name ||
    formValues.useWhen !== (profile.useWhen || "");

  const profileTabs: { id: TabId; label: string; badge?: string | number }[] = [
    { id: "profile", label: "Profile" },
    { id: "live", label: "Live" },
    { id: "tabs", label: "Tabs", badge: tabs.length },
    { id: "logs", label: "Logs" },
  ];

  return (
    <div className="dashboard-panel flex h-full min-h-112 flex-col overflow-hidden">
      <div className="border-b border-border-subtle px-4 py-3 lg:px-5">
        <ProfileToolbar
          profile={profile}
          instance={instance}
          onLaunch={onLaunch}
          onStop={onStop || (() => {})}
          onSave={handleSave}
          onDelete={onDelete || (() => {})}
          isSaveDisabled={!formValues.name.trim() || !hasChanges}
        />
      </div>

      <div className="min-h-0 flex-1 overflow-hidden">
        <TabsLayout
          tabs={profileTabs}
          activeTab={activeTab}
          onChange={(id) => setActiveTab(id)}
        >
          {activeTab === "profile" && (
            <div className="h-full overflow-auto">
              <div className="grid gap-4 xl:grid-cols-2">
                <ProfileBasicInfoPanel
                  profile={profile}
                  onChange={handleProfileChange}
                />

                <ProfileMetaInfoPanel profile={profile} instance={instance} />
              </div>
            </div>
          )}

          {activeTab === "live" && (
            <ProfileLiveViewPanel
              instance={instance}
              tabs={tabs}
              isRunning={isRunning}
            />
          )}

          {activeTab === "tabs" && (
            <div className="flex h-full min-h-0 flex-col">
              <InstanceTabsPanel
                tabs={tabs}
                instanceId={instance?.id}
                emptyMessage={
                  isRunning ? "No tabs open." : "Instance not running."
                }
              />
            </div>
          )}

          {activeTab === "logs" && (
            <InstanceLogsPanel instanceId={instance?.id} />
          )}
        </TabsLayout>
      </div>
    </div>
  );
}