Explorar o código

feat: add group deletion

Current behaviour is to delete all the tabs from the group without
warning.
Jocelyn Boullier %!s(int64=4) %!d(string=hai) anos
pai
achega
5898a05080

+ 25 - 3
extension/sidebar.css

@@ -18,14 +18,14 @@ body,
   height: 100%;
 }
 
-#bar-menu {
+#top-menu {
   width: 100%;
   height: var(--top-menu-height);
   position: sticky;
   top: 0;
 }
 
-#bar-menu ul {
+#top-menu ul {
   background-color: var(--bar-black-color);
   color: #f9f9f2;
   list-style-type: none;
@@ -33,8 +33,11 @@ body,
   padding: 0;
 }
 
-#bar-menu li {
+#top-menu li {
   display: inline-block;
+  width: 25px;
+  height: var(--top-menu-height);
+  text-align: center;
   padding: 0 7px 0;
   border-right: solid #cfcfcf 1px;
 }
@@ -78,6 +81,11 @@ body,
   color: black;
 }
 
+.group-deletion-button {
+  margin-right: 5px;
+  text-align: center;
+  vertical-align: middle;
+}
 
 .bar-tabs {
   width: calc(100% - var(--group-bar-size));
@@ -237,3 +245,17 @@ body,
 .close-button-parent:hover .close-button-inner {
   background-color: #cccccc;
 }
+
+.shake-animation {
+  display: inline-block;
+  animation: .8s shake 1 alternate;
+}
+
+@keyframes shake {
+  0% { transform: skewX(-15deg); }
+  5% { transform: skewX(15deg); }
+  10% { transform: skewX(-15deg); }
+  15% { transform: skewX(15deg); }
+  20% { transform: skewX(0deg); }
+  100% { transform: skewX(0deg); }  
+}

+ 5 - 3
src/Background.purs

@@ -197,10 +197,12 @@ manageSidebar ref winId port = case _ of
      BT.browserHideTabs tabIdsToHide
      BT.browserShowTabs tabIds
 
+  SbDeletedGroup gid tabIds -> launchAff_ do
+     BT.browserRemove tabIds
+     liftEffect $ Runtime.postMessageJson port $ BgGroupDeleted gid
+
+
   SbDetacheTab -> pure unit
-  SbCreatedGroup -> pure unit
-  SbDeleteGroup -> pure unit
-  SbRenameGroup -> pure unit
   SbHasWindowId winId' -> pure unit
 
 

+ 4 - 4
src/Browser/Tabs.purs

@@ -23,7 +23,7 @@ import Data.Eq (class Eq)
 import Data.Function (($))
 import Data.Generic.Rep (class Generic)
 import Data.Generic.Rep.Show (genericShow)
-import Data.List (List, fromFoldable, toUnfoldable, singleton)
+import Data.List (List, fromFoldable)
 import Data.Maybe (Maybe)
 import Data.Newtype (class Newtype)
 import Data.Number.Format (toString)
@@ -134,17 +134,17 @@ browserQuery = do
 
 foreign import browserRemove' :: (Array Number) -> Effect (Promise Unit)
 
-browserRemove :: (List TabId) -> Aff Unit
+browserRemove :: (Array TabId) -> Aff Unit
 browserRemove tabs =
   let
-    tabIdsArray = toUnfoldable $ map unwrap tabs
+    tabIdsArray = map unwrap tabs
   in
     toAffE $ browserRemove' tabIdsArray
   where
   unwrap (TabId n) = n
 
 browserRemoveOne :: TabId -> Aff Unit
-browserRemoveOne tabId = browserRemove (singleton tabId)
+browserRemoveOne tabId = browserRemove [tabId]
 
 type RowUpdateProperties
   = ( active :: Boolean

+ 3 - 3
src/Model/Events.purs

@@ -9,6 +9,7 @@ import Data.Generic.Rep (class Generic)
 import Data.Generic.Rep.Show (genericShow)
 import Data.Maybe (Maybe)
 import Data.Show (class Show)
+import PureTabs.Model.Group (GroupId)
 
 
 data BackgroundEvent
@@ -20,6 +21,7 @@ data BackgroundEvent
   | BgTabActivated (Maybe TabId) TabId
   | BgTabAttached Tab
   | BgTabDetached TabId
+  | BgGroupDeleted GroupId
 
 derive instance genBackgroundEvent :: Generic BackgroundEvent _
 
@@ -32,11 +34,9 @@ data SidebarEvent
   | SbCreateTab (Maybe TabId)
   | SbMoveTab TabId Int
   | SbDetacheTab
-  | SbCreatedGroup
-  | SbDeleteGroup
-  | SbRenameGroup
   | SbHasWindowId WindowId
   | SbSelectedGroup (Array TabId)
+  | SbDeletedGroup GroupId (Array TabId)
 
 derive instance genSidebarEvent :: Generic SidebarEvent _
 

+ 24 - 0
src/Model/Group.purs

@@ -0,0 +1,24 @@
+module PureTabs.Model.Group (GroupId(..)) where
+
+
+import Prelude (class Eq, class Ord, class Show, (<>), show)
+import Data.Generic.Rep (class Generic)
+import Foreign.Class (class Decode, class Encode)
+import Foreign.Generic (defaultOptions, genericDecode, genericEncode)
+
+newtype GroupId
+  = GroupId Int
+
+derive instance eqGroupId :: Eq GroupId
+derive instance ordGroupId :: Ord GroupId
+
+instance showGroupId :: Show GroupId where 
+  show (GroupId gid) = "GroupId(" <> (show gid) <> ")"
+
+derive instance genGroupId :: Generic GroupId _
+
+instance encodeGroupId :: Encode GroupId where
+  encode x = genericEncode (defaultOptions { unwrapSingleConstructors = true }) x
+
+instance decodeGroupId :: Decode GroupId where
+  decode x = genericDecode (defaultOptions { unwrapSingleConstructors = true }) x

+ 59 - 37
src/Sidebar/Components/Bar.purs

@@ -24,25 +24,18 @@ import Halogen as H
 import Halogen.HTML as HH
 import Halogen.HTML.Events as HE
 import Halogen.HTML.Properties as HP
-import Prelude (class Eq, class Ord, class Show, flip, show, (#), (&&), (+), (-), (<<<), (<>), (==), (>>>))
+import Prelude (flip, show, (#), (&&), (+), (-), (<<<), (<>), (==), (>), (>>>))
 import PureTabs.Model.Events (SidebarEvent(..))
+import PureTabs.Model.Group (GroupId(..))
+import PureTabs.Sidebar.Component.GroupName as GroupName
+import PureTabs.Sidebar.Component.TopMenu as TopMenu
 import PureTabs.Sidebar.Tabs (Output(..))
 import PureTabs.Sidebar.Tabs as Tabs
-import Sidebar.Component.GroupName as GroupName
 import Sidebar.Utils (moveElem, whenC)
 import Web.HTML.Event.DataTransfer as DT
 import Web.HTML.Event.DragEvent as DE
 
 
-newtype GroupId
-  = GroupId Int
-
-derive instance eqGroupId :: Eq GroupId
-derive instance ordGroupId :: Ord GroupId
-
-instance showGroupId :: Show GroupId where 
-  show (GroupId gid) = "GroupId(" <> (show gid) <> ")"
-
 type Group
   = { name :: String
     , pos :: Int
@@ -60,11 +53,17 @@ data Action
   = UserSelectedGroup GroupId
   | UserRenameGroup GroupId String
   | UserCreatedGroup
+  | UserChangedDeletion Boolean
   | UserDeletedGroup GroupId
   | HandleTabsOutput GroupId Tabs.Output
   | GroupNameDragOver DE.DragEvent GroupId
   | DragEnd DE.DragEvent
 
+
+data Query a
+  = TabsQuery (Tabs.Query a)
+  | GroupDeleted GroupId a
+
 initialState :: forall i. i -> State
 initialState _ =
   let
@@ -79,15 +78,20 @@ initialState _ =
     }
 
 type Slots
-  = ( tab :: H.Slot Tabs.Query Tabs.Output GroupId, groupName :: forall unusedQuery. H.Slot unusedQuery GroupName.NewName GroupId)
+  = ( tabs :: Tabs.Slot GroupId
+    , groupName :: GroupName.Slot GroupId
+    , topMenu :: TopMenu.Slot Unit)
 
-_tab :: SProxy "tab"
-_tab = (SProxy :: _ "tab")
+_tabs :: SProxy "tabs"
+_tabs = (SProxy :: _ "tabs")
 
 _groupName :: SProxy "groupName"
 _groupName = (SProxy :: _ "groupName")
 
-component :: forall i m. MonadEffect m => MonadAff m => H.Component HH.HTML Tabs.Query i SidebarEvent m
+_topMenu :: SProxy "topMenu"
+_topMenu = (SProxy :: _ "topMenu")
+
+component :: forall i m. MonadEffect m => MonadAff m => H.Component HH.HTML Query i SidebarEvent m
 component =
   H.mkComponent
     { initialState
@@ -106,11 +110,11 @@ component =
     let 
         currentGroupShown = fromMaybe state.currentGroup state.draggedCurrentGroup
 
-        menuElem attrs text = HH.li attrs [ HH.text text]
-
-        topMenu = HH.div [ HP.id_ "bar-menu" ] [
-          HH.ul [] [menuElem [HE.onClick \_ -> Just UserCreatedGroup] "+", menuElem [] "-"]
-        ]
+        topMenu = HH.slot _topMenu unit TopMenu.component unit (
+          Just <<< case _ of 
+               TopMenu.CreateGroup -> UserCreatedGroup
+               TopMenu.ChangedDeletion value -> UserChangedDeletion value
+        )
 
         barListGroup = HH.div [ HP.id_ "bar-list" ] [HH.ul [ HP.id_ "bar-list-group"] $ 
           (M.toUnfoldable state.groups) <#> \(Tuple gid g) -> renderGroup gid (gid == currentGroupShown) g
@@ -125,7 +129,7 @@ component =
         HH.div [ HP.id_ "bar", HE.onDragEnd \evt -> Just $ DragEnd evt ] $ topMenu : barListGroup : tabsDivs 
 
   renderGroupTabs :: GroupId -> H.ComponentHTML Action Slots m
-  renderGroupTabs groupId = HH.slot _tab groupId Tabs.component unit (Just <<< (HandleTabsOutput groupId))
+  renderGroupTabs groupId = HH.slot _tabs groupId Tabs.component unit (Just <<< (HandleTabsOutput groupId))
 
   renderGroup :: GroupId -> Boolean -> Group -> H.ComponentHTML Action Slots m
   renderGroup groupId isActive group =  
@@ -133,7 +137,11 @@ component =
       HP.classes [(H.ClassName "group-name"), whenC isActive (H.ClassName "active-group")]
       , HE.onClick (\_ -> Just (UserSelectedGroup groupId))
       , HE.onDragOver \evt -> Just $ GroupNameDragOver evt groupId
-    ] [ HH.slot _groupName groupId GroupName.component group.name (\newName -> Just (UserRenameGroup groupId newName))] 
+    ] [ HH.slot _groupName groupId GroupName.component group.name 
+          case _ of 
+               GroupName.NewName newName -> Just (UserRenameGroup groupId newName)
+               GroupName.DeleteGroup -> Just (UserDeletedGroup groupId)
+    ] 
 
   handleAction :: MonadEffect m => Action -> H.HalogenM State Action Slots SidebarEvent m Unit
   handleAction = 
@@ -154,7 +162,14 @@ component =
                  s.groups 
                }
 
-         UserDeletedGroup gid -> pure unit
+         UserChangedDeletion value -> void $ H.queryAll _groupName $ H.tell $ GroupName.DeletionEnabled value
+
+         UserDeletedGroup gid -> do 
+            s <- H.get
+            if M.size s.groups > 1 then
+              H.raise $ SbDeletedGroup gid $ getTabIdsOfGroup gid s.tabsToGroup
+            else 
+              void $ H.query _groupName gid $ H.tell $ GroupName.TriedToDeleteLastGroup
 
          GroupNameDragOver dragEvent gid -> do
            let 
@@ -223,10 +238,10 @@ component =
               }
             let newIndexInGroup = getPositionTabInGroup newTabIndex toGroup s.groupTabsPositions
 
-            deletedTab' <- H.query _tab fromGroup $ H.request $ Tabs.TabDeleted tid
+            deletedTab' <- H.query _tabs fromGroup $ H.request $ Tabs.TabDeleted tid
             case deletedTab' of 
                  Just (Just (Tab tab)) -> 
-                   void $ H.query _tab toGroup $ H.tell 
+                   void $ H.query _tabs toGroup $ H.tell 
                     $ Tabs.TabCreated $ Tab (tab { index = newIndexInGroup })
                  _ -> pure unit
 
@@ -257,23 +272,29 @@ component =
              newIndex # maybe (pure unit) \idx -> H.raise $ SbMoveTab tid idx 
 
  
+handleQuery :: forall act a m. Query a -> H.HalogenM State act Slots SidebarEvent m (Maybe a)
+handleQuery = case _ of 
+   TabsQuery q -> handleTabsQuery q
+
+   GroupDeleted gid a -> do 
+      H.modify_ \s -> s { groups = M.delete gid s.groups }
+      pure $ Just a
 
-  handleQuery :: forall act a. Tabs.Query a -> H.HalogenM State act Slots SidebarEvent m (Maybe a)
-  handleQuery = case _ of
+
+handleTabsQuery :: forall act a m. Tabs.Query a -> H.HalogenM State act Slots SidebarEvent m (Maybe a)
+handleTabsQuery = case _ of
 
     Tabs.InitialTabList tabs a -> do
        s <- H.modify (\s -> 
          let 
              tabIdGroup = tabs <#> \(Tab t) -> Tuple t.id s.currentGroup
           in
-         s 
-         { tabsToGroup = M.fromFoldable tabIdGroup
-         , groupTabsPositions = tabIdGroup
-         }
+         s { tabsToGroup = M.fromFoldable tabIdGroup , groupTabsPositions = tabIdGroup }
        )
        let activatedTab = tabs # A.filter (\(Tab t) -> t.active) >>> A.head
        void $ tellChild s.currentGroup $ Tabs.InitialTabList tabs
-       activatedTab # maybe (pure unit) \(Tab t) -> void $ tellChild s.currentGroup $ Tabs.TabActivated Nothing t.id
+       activatedTab # maybe (pure unit) \(Tab t) -> 
+         void $ tellChild s.currentGroup $ Tabs.TabActivated Nothing t.id
        pure (Just a)
 
     Tabs.TabCreated (Tab tab) a -> do 
@@ -307,7 +328,7 @@ component =
                           (Tuple tid s.currentGroup)
                           s.groupTabsPositions
                        })
-         void $ H.query _tab gid $ H.request $ Tabs.TabDeleted tid
+         void $ H.query _tabs gid $ H.request $ Tabs.TabDeleted tid
        pure (Just (reply Nothing))
 
     Tabs.TabActivated prevTid' tid a -> do 
@@ -341,14 +362,14 @@ component =
        pure (Just a)
 
     Tabs.TabDetached tid a -> do 
-       handleQuery $ Tabs.TabDeleted tid \_ -> a
+       handleTabsQuery $ Tabs.TabDeleted tid \_ -> a
 
     Tabs.TabAttached tab a -> do 
-       handleQuery $ Tabs.TabCreated tab a
+       handleTabsQuery $ Tabs.TabCreated tab a
 
     where
         tellChild :: GroupId -> (H.Tell Tabs.Query) -> H.HalogenM State act Slots SidebarEvent m (Maybe Unit)
-        tellChild gid q = H.query _tab gid $ H.tell q
+        tellChild gid q = H.query _tabs gid $ H.tell q
         -- 
         -- requestChild :: GroupId -> (H.Request Tabs.Query) -> H.HalogenM State act Slots SidebarEvent M (Maybe a)
         -- requestChild gid q = H.request 
@@ -363,6 +384,7 @@ component =
                Just groupId -> f groupId
                Nothing -> pure unit
 
+
 getPositionTabInGroup
   :: Int
   -> GroupId
@@ -390,7 +412,7 @@ getTabIdsOfGroup gid =
   >>> A.filter (\(Tuple tid gid') -> gid' == gid)
   >>> map T.fst
 
---| Obtain the window index of the last tab of a group.
+-- | Obtain the window index of the last tab of a group.
 lastWinTabIndexInGroup 
   :: GroupId
   -> Array (Tuple TabId GroupId)

+ 50 - 9
src/Sidebar/Components/GroupName.purs

@@ -1,11 +1,13 @@
-module Sidebar.Component.GroupName (component, NewName) where
+module PureTabs.Sidebar.Component.GroupName (component, Output(..), Query(..), Slot) where
 
 
 import Control.Category ((<<<))
 import Data.Maybe (Maybe(..), maybe)
 import Data.String.CodeUnits (length)
 import Data.Tuple.Nested ((/\))
-import Effect.Aff.Class (class MonadAff)
+import Effect.Aff (Milliseconds(..))
+import Effect.Aff as Aff
+import Effect.Aff.Class (class MonadAff, liftAff)
 import Halogen (liftEffect)
 import Halogen as H
 import Halogen.HTML as HH
@@ -14,24 +16,51 @@ import Halogen.HTML.Properties as HP
 import Halogen.Hooks as Hooks
 import Halogen.Query.Input as HQI
 import Prelude (bind, discard, otherwise, pure, unit, ($), (==))
+import Sidebar.Utils (whenC)
 import Web.Event.Event as E
 import Web.Event.EventTarget as ET
 import Web.HTML.HTMLElement (focus) as Web
 import Web.UIEvent.KeyboardEvent as KE
 
-type NewName = String
+type Slot a = H.Slot Query Output a
+
+data Output 
+  = NewName String
+  | DeleteGroup
+
+data Query a
+  = DeletionEnabled Boolean a
+  | TriedToDeleteLastGroup a
 
 foreign import targetValue :: ET.EventTarget -> String
 
 component
-  :: forall unusedQuery anyMonad
-   . MonadAff anyMonad
-  => H.Component HH.HTML unusedQuery String NewName anyMonad
+  :: forall m
+   . MonadAff m
+  => H.Component HH.HTML Query String Output m
 component = Hooks.component \rec name -> Hooks.do 
   isRenaming /\ isRenamingIdx <- Hooks.useState false 
   initialName /\ initialNameIdx <- Hooks.useState name 
   chars /\ charsIdx <- Hooks.useState name
 
+  deletionEnabled /\ deletionEnabledIdx <- Hooks.useState false
+  triedToDelete /\ triedToDeleteIdx <- Hooks.useState false
+
+  Hooks.useQuery rec.queryToken case _ of 
+
+    DeletionEnabled value a -> do 
+       Hooks.put deletionEnabledIdx value
+       pure Nothing
+
+    TriedToDeleteLastGroup a -> do
+       Hooks.put triedToDeleteIdx true
+       -- TODO: Add a debounce for setting triedToDelete to false. This will
+       -- avoid the animation getting cancelled if we click multiple times too
+       -- fast on the button.
+       liftAff $ Aff.delay $ Milliseconds 800.0
+       Hooks.put triedToDeleteIdx false
+       pure Nothing
+
   let 
       onKeyEvent keyEvent 
         | KE.key keyEvent == "Enter" = 
@@ -42,7 +71,7 @@ component = Hooks.component \rec name -> Hooks.do
               _ -> do
                  Hooks.put isRenamingIdx false 
                  Hooks.put initialNameIdx chars
-                 Hooks.raise rec.outputToken chars
+                 Hooks.raise rec.outputToken $ NewName chars
         | KE.key keyEvent == "Escape" = 
           Just do 
              Hooks.put charsIdx initialName
@@ -54,13 +83,25 @@ component = Hooks.component \rec name -> Hooks.do
          let value = targetValue target
          Just $ Hooks.put charsIdx value
 
+      groupName = HH.text chars
+      node = 
+        if deletionEnabled then 
+          [HH.span [
+            HP.class_ $ H.ClassName "group-deletion-button"
+            , HE.onClick \_ -> Just $ Hooks.raise rec.outputToken DeleteGroup
+          ] [HH.text "✖"], groupName]
+        else
+          [groupName]
+
+
   Hooks.pure $
       if isRenaming then 
         HH.input [ HP.type_ HP.InputText, HP.value chars, HE.onKeyUp onKeyEvent, HE.onInput onInput, HP.ref (HQI.RefLabel "input") ] 
       else 
         HH.span [ 
-          HE.onDoubleClick \_ -> Just $ do 
+          HP.class_ $ whenC triedToDelete (H.ClassName "shake-animation")
+          , HE.onDoubleClick \_ -> if deletionEnabled then Nothing else Just $ do 
              Hooks.put isRenamingIdx true 
              elem <- Hooks.getHTMLElementRef (HQI.RefLabel "input")
              maybe (pure unit) (liftEffect <<< Web.focus) elem
-        ] [HH.text chars]
+        ] node

+ 3 - 1
src/Sidebar/Components/Tabs.purs

@@ -1,4 +1,4 @@
-module PureTabs.Sidebar.Tabs (component, Query(..), Output(..)) where
+module PureTabs.Sidebar.Tabs (component, Query(..), Output(..), Slot) where
 
 import Browser.Tabs (Tab(..), TabId, showTabId)
 import Browser.Tabs.OnUpdated (ChangeInfo(..), ChangeInfoRec)
@@ -42,6 +42,8 @@ import Web.HTML.Event.DragEvent as DE
 import Web.HTML.HTMLElement (toElement) as DOM
 import Web.UIEvent.MouseEvent as ME
 
+type Slot a = H.Slot Query Output a
+
 data Query a
   = InitialTabList (Array Tab) a
   | TabCreated Tab a

+ 41 - 0
src/Sidebar/Components/TopMenu.purs

@@ -0,0 +1,41 @@
+module PureTabs.Sidebar.Component.TopMenu (component, TopMenuAction(..), Slot) where 
+
+import Prelude (($), bind, not)
+
+import Data.Tuple.Nested ((/\))
+import Data.Maybe (Maybe(..))
+import Halogen as H
+import Halogen.HTML as HH
+import Halogen.HTML.Events as HE
+import Halogen.HTML.Properties as HP
+import Halogen.Hooks as Hooks
+
+
+type Slot a = forall q. H.Slot q TopMenuAction a
+
+
+data TopMenuAction
+  = CreateGroup
+  | ChangedDeletion Boolean
+
+
+component 
+  :: forall unusedQuery unusedInput anyMonad
+   . H.Component HH.HTML unusedQuery unusedInput TopMenuAction anyMonad
+component = Hooks.component \rec _ -> Hooks.do
+  isDeleting /\ isDeletingIdx <- Hooks.useState false
+
+  let menuElem attrs text = HH.li attrs [ HH.text text ]
+
+  Hooks.pure $ 
+    HH.div [ HP.id_ "top-menu" ] [
+      HH.ul [] [
+        menuElem [HE.onClick \_ -> Just $ Hooks.raise rec.outputToken CreateGroup] "+", 
+        menuElem [
+          HE.onClick \_ -> Just $ do
+             isNowDeleting <- Hooks.modify isDeletingIdx (not)
+             Hooks.raise rec.outputToken $ ChangedDeletion isNowDeleting
+       ] if isDeleting then "✓" else "-"
+      ]
+    ]
+

+ 14 - 9
src/Sidebar/Sidebar.purs

@@ -43,43 +43,48 @@ onBackgroundMsgProducer port =
   CRA.produce \emitter ->
     liftEffect $ void $ Runtime.onMessageJsonAddListener port (emit emitter)
 
-onBackgroundMsgConsumer :: (forall a. Tabs.Query a -> Aff (Maybe a)) -> CR.Consumer BackgroundEvent Aff Unit
+
+onBackgroundMsgConsumer :: (forall a. Bar.Query a -> Aff (Maybe a)) -> CR.Consumer BackgroundEvent Aff Unit
 onBackgroundMsgConsumer query =
   CR.consumer
     $ case _ of
 
         BgInitialTabList tabs -> do
-          void $ query $ H.tell $ Tabs.InitialTabList tabs
+          void $ query $ H.tell $ \q -> Bar.TabsQuery (Tabs.InitialTabList tabs q) 
           pure Nothing
 
         BgTabCreated tab -> do
-          void $ query $ H.tell $ Tabs.TabCreated tab
+          void $ query $ H.tell $ \q -> Bar.TabsQuery (Tabs.TabCreated tab q)
           pure Nothing
 
         BgTabDeleted tabId -> do
-          void $ query $ H.request $ Tabs.TabDeleted tabId
+          void $ query $ H.request $ \q -> Bar.TabsQuery (Tabs.TabDeleted tabId q)
           pure Nothing
 
         BgTabActivated prev next -> do
-          void $ query $ H.tell $ Tabs.TabActivated prev next
+          void $ query $ H.tell $ \q -> Bar.TabsQuery (Tabs.TabActivated prev next q)
           pure Nothing
 
         BgTabMoved tabId prev next -> do
-          void $ query $ H.tell $ Tabs.TabMoved tabId next
+          void $ query $ H.tell $ \q -> Bar.TabsQuery (Tabs.TabMoved tabId next q)
           pure Nothing
 
         BgTabUpdated tabId cinfo tab -> do
-          void $ query $ H.tell $ Tabs.TabInfoChanged tabId $ fillChangeInfoIfEmpty tab cinfo
+          void $ query $ H.tell $ \q -> Bar.TabsQuery (Tabs.TabInfoChanged tabId (fillChangeInfoIfEmpty tab cinfo) q)
           pure Nothing
 
         BgTabDetached tabId -> do 
-          void $ query $ H.tell $ Tabs.TabDetached tabId
+          void $ query $ H.tell $ \q -> Bar.TabsQuery (Tabs.TabDetached tabId q)
           pure Nothing
 
         BgTabAttached tab -> do 
-          void $ query $ H.tell $ Tabs.TabAttached tab
+          void $ query $ H.tell $ \q -> Bar.TabsQuery (Tabs.TabAttached tab q)
           pure Nothing
 
+        BgGroupDeleted gid -> do
+           void $ query $ H.tell $ Bar.GroupDeleted gid
+           pure Nothing
+
 -- | Workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=1640112
 -- | In case the ChangeInfo only contains an update for the status field to "complete",
 -- | we generate a new one with all the information from the tab.