Feature/fsg gamma team ui fix #3
@@ -1074,7 +1074,14 @@ class MainWindow(QMainWindow):
|
||||
self.workspace.refresh() # re-list projects + threads on entry
|
||||
widget = self._page_widgets[page]
|
||||
if sub is not None and hasattr(widget, "select_subtab"):
|
||||
widget.select_subtab(sub)
|
||||
# Enforce the project gate here rather than at each entry point. A
|
||||
# greyed rail row cannot be clicked, but _goto is also reached from
|
||||
# RECENTS and from startup restore, and it used to open a sub-tab
|
||||
# the gate was holding shut — page shown, tab strip still hiding it.
|
||||
if hasattr(widget, "subtab_available") and not widget.subtab_available(sub):
|
||||
self.statusBar().showMessage(tr("app.nav.needs_project"), 4000)
|
||||
else:
|
||||
widget.select_subtab(sub)
|
||||
# Move the highlight with the content, however navigation was triggered —
|
||||
# a programmatic _goto used to leave it on whatever was clicked last.
|
||||
if not self._nav_building:
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
"""With no project chosen, the gated screens must stay shut on every route.
|
||||
|
||||
The redesign shows Cowork and GraphRAG at all times instead of making them
|
||||
appear and disappear. That is a presentation change only — the gate is the same
|
||||
`isTabVisible` state as before — so this asserts the gate still actually holds,
|
||||
and holds for programmatic jumps too, not just for the greyed rail rows.
|
||||
|
||||
Runs against an EMPTY home, not a copy of the real one: with any project on
|
||||
disk the gate is open and the test proves nothing.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(REPO.parent))
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||
os.environ.setdefault("QT_QPA_PLATFORM", "offscreen")
|
||||
|
||||
sandbox = Path(tempfile.mkdtemp(prefix="cowork-gate-"))
|
||||
(sandbox / ".cowork_local").mkdir(parents=True, exist_ok=True)
|
||||
for _var in ("USERPROFILE", "HOME"):
|
||||
os.environ[_var] = str(sandbox)
|
||||
os.environ.pop("HOMEDRIVE", None)
|
||||
os.environ.pop("HOMEPATH", None)
|
||||
|
||||
from capture_screens import _apply_theme, _freeze_schedulers, _load_fonts # noqa: E402
|
||||
|
||||
|
||||
def main() -> int:
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QApplication
|
||||
|
||||
app = QApplication([])
|
||||
_load_fonts()
|
||||
_freeze_schedulers()
|
||||
_apply_theme(app)
|
||||
|
||||
from cowork_local.config import CONFIG_DIR
|
||||
assert str(sandbox) in str(CONFIG_DIR), f"isolation failed: {CONFIG_DIR}"
|
||||
|
||||
from cowork_local.app import MainWindow
|
||||
from cowork_local.config import AppConfig
|
||||
from cowork_local.i18n import set_language
|
||||
from cowork_local.state import AppContext
|
||||
|
||||
set_language("vi")
|
||||
win = MainWindow(AppContext(AppConfig.load()), user_name="local")
|
||||
win.resize(1400, 900)
|
||||
win.show()
|
||||
app.processEvents()
|
||||
|
||||
fails = []
|
||||
n_projects = len(win.workspace.project_choices())
|
||||
print(f"project tren dia: {n_projects}")
|
||||
if n_projects:
|
||||
print("FAIL home khong rong — phep thu vo nghia")
|
||||
sys.stdout.flush()
|
||||
os._exit(1)
|
||||
|
||||
tree = win.nav
|
||||
rows = [(i, tree.topLevelItem(i)) for i in range(tree.topLevelItemCount())]
|
||||
locked = [(i, it) for i, it in rows if it.isDisabled()]
|
||||
print("dong bi khoa :", [it.text(0) for _i, it in locked])
|
||||
print("dong mo binh thuong:", [it.text(0) for _i, it in rows if not it.isDisabled()])
|
||||
if not locked:
|
||||
fails.append("khong project nao ma khong dong nao bi khoa")
|
||||
|
||||
for _i, it in locked:
|
||||
if not it.toolTip(0):
|
||||
fails.append(f"dong khoa '{it.text(0)}' khong noi ly do")
|
||||
|
||||
for i, it in locked:
|
||||
label = it.text(0)
|
||||
data = it.data(0, Qt.UserRole) or {}
|
||||
before = win.workspace.current_subtab()
|
||||
|
||||
tree.setCurrentItem(it)
|
||||
app.processEvents()
|
||||
if win.workspace.current_subtab() != before:
|
||||
fails.append(f"bam duoc vao '{label}' du dang khoa")
|
||||
|
||||
# the route a greyed row does not guard: a jump from code
|
||||
win._goto(data.get("page", 0), data.get("sub"))
|
||||
app.processEvents()
|
||||
landed = win.workspace.current_subtab()
|
||||
if landed == data.get("sub"):
|
||||
fails.append(f"_goto mo duoc '{label}' trong khi cong dang dong")
|
||||
print(f" '{label}': bam -> {before}, _goto -> {landed} "
|
||||
f"(tab hien = {win.workspace.tabs.isTabVisible(data.get('sub'))})")
|
||||
|
||||
# controls that would act on a project must be off too
|
||||
for name, widget in (("+ chat moi", win.nav_new_chat),
|
||||
("chon project", win.nav_project_btn)):
|
||||
if widget.isEnabled():
|
||||
fails.append(f"'{name}' van bam duoc khi chua co project")
|
||||
print(f"+ chat moi bat={win.nav_new_chat.isEnabled()} "
|
||||
f"tooltip={win.nav_new_chat.toolTip()!r}")
|
||||
|
||||
print()
|
||||
for f in fails:
|
||||
print("FAIL " + f)
|
||||
print("PASS cong project van giu, ca khi bam lan khi goi tu code" if not fails
|
||||
else f"{len(fails)} problem(s)")
|
||||
sys.stdout.flush()
|
||||
os._exit(1 if fails else 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -67,6 +67,14 @@ class WorkspaceTab(QWidget):
|
||||
self.tabs.isTabVisible(i))
|
||||
for i in range(self.tabs.count())]
|
||||
|
||||
def subtab_available(self, index: int) -> bool:
|
||||
"""False while the project gate is holding this sub-tab shut.
|
||||
|
||||
The rail greys those rows out, but that only guards the rail. This lets
|
||||
every other route ask the same question of the same state.
|
||||
"""
|
||||
return bool(0 <= index < self.tabs.count() and self.tabs.isTabVisible(index))
|
||||
|
||||
def select_subtab(self, index: int) -> None:
|
||||
if 0 <= index < self.tabs.count():
|
||||
self.tabs.setCurrentIndex(index)
|
||||
|
||||
Reference in New Issue
Block a user