mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-31 18:18:02 +01:00
delete block and close tab working
This commit is contained in:
parent
e6d7a4e674
commit
3f45945cb4
@ -34,7 +34,7 @@ Now to run the dev version of the app:
|
|||||||
wails3 dev
|
wails3 dev
|
||||||
```
|
```
|
||||||
|
|
||||||
You should see a very poorly laid out app :)
|
You should see the app!
|
||||||
|
|
||||||
Now to build a MacOS application:
|
Now to build a MacOS application:
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ const Block = ({ tabId, blockId }: { tabId: string; blockId: string }) => {
|
|||||||
const [dims, setDims] = React.useState({ width: 0, height: 0 });
|
const [dims, setDims] = React.useState({ width: 0, height: 0 });
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
// TODO
|
WOS.DeleteBlock(blockId);
|
||||||
}
|
}
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
|
@ -178,6 +178,7 @@ function updateWaveObject(update: WaveObjUpdate) {
|
|||||||
waveObjectValueCache.set(oref, wov);
|
waveObjectValueCache.set(oref, wov);
|
||||||
}
|
}
|
||||||
if (update.updatetype == "delete") {
|
if (update.updatetype == "delete") {
|
||||||
|
console.log("WaveObj deleted", oref);
|
||||||
globalStore.set(wov.dataAtom, { value: null, loading: false });
|
globalStore.set(wov.dataAtom, { value: null, loading: false });
|
||||||
} else {
|
} else {
|
||||||
if (!isValidWaveObj(update.obj)) {
|
if (!isValidWaveObj(update.obj)) {
|
||||||
@ -188,6 +189,7 @@ function updateWaveObject(update: WaveObjUpdate) {
|
|||||||
if (curValue.value != null && curValue.value.version >= update.obj.version) {
|
if (curValue.value != null && curValue.value.version >= update.obj.version) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
console.log("WaveObj updated", oref);
|
||||||
globalStore.set(wov.dataAtom, { value: update.obj, loading: false });
|
globalStore.set(wov.dataAtom, { value: update.obj, loading: false });
|
||||||
}
|
}
|
||||||
wov.holdTime = Date.now() + defaultHoldTime;
|
wov.holdTime = Date.now() + defaultHoldTime;
|
||||||
@ -226,12 +228,14 @@ Events.On("waveobj:update", (event: any) => {
|
|||||||
|
|
||||||
function wrapObjectServiceCall<T>(fnName: string, ...args: any[]): Promise<T> {
|
function wrapObjectServiceCall<T>(fnName: string, ...args: any[]): Promise<T> {
|
||||||
const uiContext = globalStore.get(atoms.uiContext);
|
const uiContext = globalStore.get(atoms.uiContext);
|
||||||
|
const startTs = Date.now();
|
||||||
let prtn = $Call.ByName(
|
let prtn = $Call.ByName(
|
||||||
"github.com/wavetermdev/thenextwave/pkg/service/objectservice.ObjectService." + fnName,
|
"github.com/wavetermdev/thenextwave/pkg/service/objectservice.ObjectService." + fnName,
|
||||||
uiContext,
|
uiContext,
|
||||||
...args
|
...args
|
||||||
);
|
);
|
||||||
prtn = prtn.then((val) => {
|
prtn = prtn.then((val) => {
|
||||||
|
console.log("Call", fnName, Date.now() - startTs + "ms");
|
||||||
if (val.updates) {
|
if (val.updates) {
|
||||||
updateWaveObjects(val.updates);
|
updateWaveObjects(val.updates);
|
||||||
}
|
}
|
||||||
@ -249,18 +253,26 @@ function getStaticObjectValue<T>(oref: string, getFn: jotai.Getter): T {
|
|||||||
return atomVal.value;
|
return atomVal.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
function AddTabToWorkspace(tabName: string, activateTab: boolean): Promise<{ tabId: string }> {
|
export function AddTabToWorkspace(tabName: string, activateTab: boolean): Promise<{ tabId: string }> {
|
||||||
return wrapObjectServiceCall("AddTabToWorkspace", tabName, activateTab);
|
return wrapObjectServiceCall("AddTabToWorkspace", tabName, activateTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SetActiveTab(tabId: string): Promise<void> {
|
export function SetActiveTab(tabId: string): Promise<void> {
|
||||||
return wrapObjectServiceCall("SetActiveTab", tabId);
|
return wrapObjectServiceCall("SetActiveTab", tabId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function CreateBlock(blockDef: BlockDef, rtOpts: RuntimeOpts): Promise<{ blockId: string }> {
|
export function CreateBlock(blockDef: BlockDef, rtOpts: RuntimeOpts): Promise<{ blockId: string }> {
|
||||||
return wrapObjectServiceCall("CreateBlock", blockDef, rtOpts);
|
return wrapObjectServiceCall("CreateBlock", blockDef, rtOpts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function DeleteBlock(blockId: string): Promise<void> {
|
||||||
|
return wrapObjectServiceCall("DeleteBlock", blockId);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CloseTab(tabId: string): Promise<void> {
|
||||||
|
return wrapObjectServiceCall("CloseTab", tabId);
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
makeORef,
|
makeORef,
|
||||||
useWaveObject,
|
useWaveObject,
|
||||||
@ -272,7 +284,4 @@ export {
|
|||||||
updateWaveObjects,
|
updateWaveObjects,
|
||||||
cleanWaveObjectCache,
|
cleanWaveObjectCache,
|
||||||
getStaticObjectValue,
|
getStaticObjectValue,
|
||||||
AddTabToWorkspace,
|
|
||||||
SetActiveTab,
|
|
||||||
CreateBlock,
|
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ import { atoms } from "@/store/global";
|
|||||||
import * as WOS from "@/store/wos";
|
import * as WOS from "@/store/wos";
|
||||||
|
|
||||||
import "./tab.less";
|
import "./tab.less";
|
||||||
import { CenteredLoadingDiv } from "../element/quickelems";
|
import { CenteredDiv, CenteredLoadingDiv } from "../element/quickelems";
|
||||||
|
|
||||||
const TabContent = ({ tabId }: { tabId: string }) => {
|
const TabContent = ({ tabId }: { tabId: string }) => {
|
||||||
const [tabData, tabLoading] = WOS.useWaveObjectValue<Tab>(WOS.makeORef("tab", tabId));
|
const [tabData, tabLoading] = WOS.useWaveObjectValue<Tab>(WOS.makeORef("tab", tabId));
|
||||||
@ -16,7 +16,11 @@ const TabContent = ({ tabId }: { tabId: string }) => {
|
|||||||
return <CenteredLoadingDiv />;
|
return <CenteredLoadingDiv />;
|
||||||
}
|
}
|
||||||
if (!tabData) {
|
if (!tabData) {
|
||||||
return <div className="tabcontent">Tab not found</div>;
|
return (
|
||||||
|
<div className="tabcontent">
|
||||||
|
<CenteredDiv>Tab Not Found</CenteredDiv>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="tabcontent">
|
<div className="tabcontent">
|
||||||
|
@ -55,9 +55,24 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
border-right: 1px solid var(--border-color);
|
border-right: 1px solid var(--border-color);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
background-color: var(--highlight-bg-color);
|
background-color: var(--highlight-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.active:hover .tab-close {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-close {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
padding: 5px;
|
||||||
|
right: 2px;
|
||||||
|
top: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-add {
|
.tab-add {
|
||||||
|
@ -14,17 +14,22 @@ import "./workspace.less";
|
|||||||
function Tab({ tabId }: { tabId: string }) {
|
function Tab({ tabId }: { tabId: string }) {
|
||||||
const windowData = jotai.useAtomValue(atoms.waveWindow);
|
const windowData = jotai.useAtomValue(atoms.waveWindow);
|
||||||
const [tabData, tabLoading] = WOS.useWaveObjectValue<Tab>(WOS.makeORef("tab", tabId));
|
const [tabData, tabLoading] = WOS.useWaveObjectValue<Tab>(WOS.makeORef("tab", tabId));
|
||||||
function setActiveTab(tabId: string) {
|
function setActiveTab() {
|
||||||
if (tabId == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WOS.SetActiveTab(tabId);
|
WOS.SetActiveTab(tabId);
|
||||||
}
|
}
|
||||||
|
function handleCloseTab() {
|
||||||
|
WOS.CloseTab(tabId);
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx("tab", { active: tabData != null && windowData.activetabid === tabData.oid })}
|
className={clsx("tab", { active: tabData != null && windowData.activetabid === tabData.oid })}
|
||||||
onClick={() => setActiveTab(tabData?.oid)}
|
onClick={() => setActiveTab()}
|
||||||
>
|
>
|
||||||
|
<div className="tab-close" onClick={() => handleCloseTab()}>
|
||||||
|
<div>
|
||||||
|
<i className="fa fa-solid fa-xmark" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{tabData?.name ?? "..."}
|
{tabData?.name ?? "..."}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -115,8 +120,14 @@ function WorkspaceElem() {
|
|||||||
<div className="workspace">
|
<div className="workspace">
|
||||||
<TabBar workspace={ws} />
|
<TabBar workspace={ws} />
|
||||||
<div className="workspace-tabcontent">
|
<div className="workspace-tabcontent">
|
||||||
<TabContent key={windowData.workspaceid} tabId={activeTabId} />
|
{activeTabId == "" ? (
|
||||||
<Widgets />
|
<CenteredDiv>No Active Tab</CenteredDiv>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<TabContent key={windowData.workspaceid} tabId={activeTabId} />
|
||||||
|
<Widgets />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -132,3 +132,50 @@ func (svc *ObjectService) CreateBlock(uiContext wstore.UIContext, blockDef *wsto
|
|||||||
rtn["blockid"] = blockData.OID
|
rtn["blockid"] = blockData.OID
|
||||||
return updatesRtn(ctx, rtn)
|
return updatesRtn(ctx, rtn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *ObjectService) DeleteBlock(uiContext wstore.UIContext, blockId string) (any, error) {
|
||||||
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
||||||
|
defer cancelFn()
|
||||||
|
ctx = wstore.ContextWithUpdates(ctx)
|
||||||
|
err := wstore.DeleteBlock(ctx, uiContext.ActiveTabId, blockId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error deleting block: %w", err)
|
||||||
|
}
|
||||||
|
blockcontroller.StopBlockController(blockId)
|
||||||
|
return updatesRtn(ctx, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (svc *ObjectService) CloseTab(uiContext wstore.UIContext, tabId string) (any, error) {
|
||||||
|
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
|
||||||
|
defer cancelFn()
|
||||||
|
ctx = wstore.ContextWithUpdates(ctx)
|
||||||
|
window, err := wstore.DBMustGet[*wstore.Window](ctx, uiContext.WindowId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting window: %w", err)
|
||||||
|
}
|
||||||
|
tab, err := wstore.DBMustGet[*wstore.Tab](ctx, tabId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting tab: %w", err)
|
||||||
|
}
|
||||||
|
for _, blockId := range tab.BlockIds {
|
||||||
|
blockcontroller.StopBlockController(blockId)
|
||||||
|
}
|
||||||
|
err = wstore.CloseTab(ctx, window.WorkspaceId, tabId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error closing tab: %w", err)
|
||||||
|
}
|
||||||
|
if window.ActiveTabId == tabId {
|
||||||
|
ws, err := wstore.DBMustGet[*wstore.Workspace](ctx, window.WorkspaceId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error getting workspace: %w", err)
|
||||||
|
}
|
||||||
|
var newActiveTabId string
|
||||||
|
if len(ws.TabIds) > 0 {
|
||||||
|
newActiveTabId = ws.TabIds[0]
|
||||||
|
} else {
|
||||||
|
newActiveTabId = ""
|
||||||
|
}
|
||||||
|
wstore.SetActiveTab(ctx, uiContext.WindowId, newActiveTabId)
|
||||||
|
}
|
||||||
|
return updatesRtn(ctx, nil)
|
||||||
|
}
|
||||||
|
@ -159,10 +159,12 @@ func (update WaveObjUpdate) MarshalJSON() ([]byte, error) {
|
|||||||
rtn["updatetype"] = update.UpdateType
|
rtn["updatetype"] = update.UpdateType
|
||||||
rtn["otype"] = update.OType
|
rtn["otype"] = update.OType
|
||||||
rtn["oid"] = update.OID
|
rtn["oid"] = update.OID
|
||||||
var err error
|
if update.Obj != nil {
|
||||||
rtn["obj"], err = waveobj.ToJsonMap(update.Obj)
|
var err error
|
||||||
if err != nil {
|
rtn["obj"], err = waveobj.ToJsonMap(update.Obj)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return json.Marshal(rtn)
|
return json.Marshal(rtn)
|
||||||
}
|
}
|
||||||
@ -308,9 +310,11 @@ func SetActiveTab(ctx context.Context, windowId string, tabId string) error {
|
|||||||
if window == nil {
|
if window == nil {
|
||||||
return fmt.Errorf("window not found: %q", windowId)
|
return fmt.Errorf("window not found: %q", windowId)
|
||||||
}
|
}
|
||||||
tab, _ := DBGet[*Tab](tx.Context(), tabId)
|
if tabId != "" {
|
||||||
if tab == nil {
|
tab, _ := DBGet[*Tab](tx.Context(), tabId)
|
||||||
return fmt.Errorf("tab not found: %q", tabId)
|
if tab == nil {
|
||||||
|
return fmt.Errorf("tab not found: %q", tabId)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
window.ActiveTabId = tabId
|
window.ActiveTabId = tabId
|
||||||
DBUpdate(tx.Context(), window)
|
DBUpdate(tx.Context(), window)
|
||||||
@ -340,6 +344,57 @@ func CreateBlock(ctx context.Context, tabId string, blockDef *BlockDef, rtOpts *
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func findStringInSlice(slice []string, val string) int {
|
||||||
|
for idx, v := range slice {
|
||||||
|
if v == val {
|
||||||
|
return idx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteBlock(ctx context.Context, tabId string, blockId string) error {
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
tab, _ := DBGet[*Tab](tx.Context(), tabId)
|
||||||
|
if tab == nil {
|
||||||
|
return fmt.Errorf("tab not found: %q", tabId)
|
||||||
|
}
|
||||||
|
blockIdx := findStringInSlice(tab.BlockIds, blockId)
|
||||||
|
if blockIdx == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
tab.BlockIds = append(tab.BlockIds[:blockIdx], tab.BlockIds[blockIdx+1:]...)
|
||||||
|
DBUpdate(tx.Context(), tab)
|
||||||
|
DBDelete(tx.Context(), "block", blockId)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func CloseTab(ctx context.Context, workspaceId string, tabId string) error {
|
||||||
|
return WithTx(ctx, func(tx *TxWrap) error {
|
||||||
|
ws, _ := DBGet[*Workspace](tx.Context(), workspaceId)
|
||||||
|
if ws == nil {
|
||||||
|
return fmt.Errorf("workspace not found: %q", workspaceId)
|
||||||
|
}
|
||||||
|
tab, _ := DBGet[*Tab](tx.Context(), tabId)
|
||||||
|
if tab == nil {
|
||||||
|
return fmt.Errorf("tab not found: %q", tabId)
|
||||||
|
}
|
||||||
|
tabIdx := findStringInSlice(ws.TabIds, tabId)
|
||||||
|
if tabIdx == -1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ws.TabIds = append(ws.TabIds[:tabIdx], ws.TabIds[tabIdx+1:]...)
|
||||||
|
DBUpdate(tx.Context(), ws)
|
||||||
|
DBDelete(tx.Context(), "tab", tabId)
|
||||||
|
for _, blockId := range tab.BlockIds {
|
||||||
|
DBDelete(tx.Context(), "block", blockId)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func EnsureInitialData() error {
|
func EnsureInitialData() error {
|
||||||
// does not need to run in a transaction since it is called on startup
|
// does not need to run in a transaction since it is called on startup
|
||||||
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
ctx, cancelFn := context.WithTimeout(context.Background(), 2*time.Second)
|
||||||
|
Loading…
Reference in New Issue
Block a user