Skip to content

Commit

Permalink
feat(client): board support show project tree and model list
Browse files Browse the repository at this point in the history
  • Loading branch information
jialeicui committed Jul 13, 2022
1 parent 7e44f14 commit 8dc75da
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 73 deletions.
4 changes: 4 additions & 0 deletions client/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ black-format:
isort-format:
isort $(PY_CHANGED_FILES)

.POHNY: format
format:
black --config pyproject.toml . && isort .

.POHNY: ci-format-checker
ci-format-checker:
echo "run black"
Expand Down
2 changes: 1 addition & 1 deletion client/starwhale/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@
from starwhale.core.job.cli import job_cmd
from starwhale.utils.config import load_swcli_config
from starwhale.core.model.cli import model_cmd
from starwhale.cli.board.board import open_board
from starwhale.core.dataset.cli import dataset_cmd
from starwhale.core.project.cli import project_cmd
from starwhale.core.runtime.cli import runtime_cmd
from starwhale.core.instance.cli import instance_cmd

from .mngt import add_mngt_command
from .board import open_board


def create_sw_cli() -> click.core.Group:
Expand Down
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@
from textual.widget import Widget, RenderableType
from textual.widgets import Footer, Header, ScrollView

from ..utils import pretty_bytes, snake_to_camel
from ..consts import STANDALONE_INSTANCE
from ..core.model.view import ModelTermView
from ..core.instance.view import InstanceTermView
from ..core.project.model import Project
from ..core.instance.model import Instance, CloudInstance, StandaloneInstance
from starwhale.utils import pretty_bytes, snake_to_camel
from starwhale.core.model.view import ModelTermView

from .project_tree import ProjectTree, ProjectClick


@dataclass
Expand Down Expand Up @@ -58,6 +56,7 @@ def watch_data(self):
pass

def render(self) -> Table:
self.app.sub_title = self.__class__.__name__
return self._info or self.table

def reload(self) -> None:
Expand Down Expand Up @@ -122,7 +121,8 @@ async def key_h(self):
class Models(TableWidget):
"""Models represents starwhale model view"""

def __init__(self, **kwargs) -> None:
# TODO use constance
def __init__(self, uri: str = "local/self", **kwargs) -> None:
super().__init__(**kwargs)
self.render_fn = [
Column("name"),
Expand All @@ -131,89 +131,39 @@ def __init__(self, **kwargs) -> None:
Column("size", render=lambda _, x: pretty_bytes(x["size"])),
Column("created_at", "Created At"),
]
self.reload()

def reloadImpl(self) -> None:
self.data, _ = ModelTermView("local/self").list()


class Projects(TableWidget):
"""Projects represents starwhale project view"""

def __init__(self, uri: str, **kwargs):
super().__init__(**kwargs)
self.render_fn = [
Column("name"),
Column("owner"),
Column("created_at", "Created At"),
]
self.uri = uri
self.reload()

self.current = None

def reloadImpl(self) -> None:
self.data, _ = Project.list(self.uri)


class Instances(TableWidget):
"""Instance represents starwhale instance view"""

def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.render_fn = [
Column("name"),
Column("uri"),
Column("user_name"),
Column("user_role"),
Column("current_project"),
Column("updated_at", "Last Update"),
]
self.reload()

self.current = None

show_projects: Reactive[bool] = Reactive(False)

def reloadImpl(self) -> None:
self.data = InstanceTermView().list()

def get_current(self) -> Instance:
row = self.data[self.cursor_line]
# TODO refine instance detection logic
name = row["name"]
if name == STANDALONE_INSTANCE:
return StandaloneInstance()
return CloudInstance(name)

async def key_enter(self):
self.show_projects = True

def key_h(self):
self.show_projects = False

def render(self) -> Table:
if self.show_projects:
return Projects(uri=self.get_current().uri.raw).render()
return super().render()
self.data, _ = ModelTermView.list(self.uri)


class Dashboard(App):
def __init__(self, **kwargs):
self.body: t.Union[ScrollView, None] = None
self.table = Instances()
super().__init__(**kwargs)

async def on_load(self, event: events.Load) -> None:
pass

async def on_mount(self, event: events.Mount) -> None:
self.body = ScrollView()
await self.view.dock(Header(style=""), edge="top")
await self.view.dock(Footer(), edge="bottom")
await self.view.dock(self.table, edge="right")
await self.view.dock(
ScrollView(ProjectTree("Starwhale", "projects")),
edge="left",
size=30,
name="sidebar",
)
await self.view.dock(self.body, edge="top")

async def on_key(self, event: events.Key) -> None:
await self.table.on_key(event)
pass

async def handle_project_click(self, message: ProjectClick) -> None:
self.model = Models(message.uri)
await self.body.update(self.model)
await self.model.focus()


@click.command(
Expand Down
56 changes: 56 additions & 0 deletions client/starwhale/cli/board/project_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from dataclasses import dataclass

import rich.repr
from textual import events
from textual._types import MessageTarget
from textual.widget import Message
from textual.widgets import TreeClick, TreeControl

from starwhale.core.instance.view import InstanceTermView
from starwhale.core.project.model import Project


@dataclass
class ProjectEntry:
path: str
is_project: bool


@rich.repr.auto
class ProjectClick(Message, bubble=True):
def __init__(self, sender: MessageTarget, uri: str) -> None:
self.uri = uri
super().__init__(sender)


class ProjectTree(TreeControl[ProjectEntry]):
def __init__(self, uri: str, name: str):
data = ProjectEntry("", False)
super().__init__(uri, name=name, data=data)

async def on_mount(self, event: events.Mount) -> None:
ins = InstanceTermView().list()
for i in ins:
await self.root.add(i["name"], ProjectEntry(i["name"], False))
await self.root.expand()
self.refresh(layout=True)

async def handle_tree_click(self, message: TreeClick[ProjectEntry]) -> None:
dir_entry = message.node.data
# root entry
if not dir_entry.path:
return
if dir_entry.is_project:
await self.emit(ProjectClick(self, dir_entry.path))
else:
if not message.node.loaded:
ins = message.node.data.path
ps, _ = Project.list(ins)
for i in ps:
await message.node.add(
i["name"], ProjectEntry(f"{ins}/{i['name']}", True)
)
await message.node.expand()
message.node.loaded = True
else:
await message.node.toggle()

0 comments on commit 8dc75da

Please sign in to comment.