Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/Options.vue
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ function deleteGroup(group: GroupConfiguration) {
function addGroup(
title: string,
color: `${chrome.tabGroups.Color}`,
{ strict, merge }: SaveOptions,
{ strict, merge, minTabsToGroup }: SaveOptions,
) {
const id = crypto.randomUUID()

Expand All @@ -113,6 +113,7 @@ function addGroup(
options: {
strict,
merge,
minTabsToGroup,
},
})

Expand Down
2 changes: 1 addition & 1 deletion src/Popup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ async function createFromCurrentGroup(
title,
color,
matchers: [],
options: { strict: false, merge: false },
options: { strict: false, merge: false, minTabsToGroup: 2 },
},
])

Expand Down
46 changes: 24 additions & 22 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,25 +38,6 @@ const augmentedGroupConfigurations = computed(() =>
})),
)

const chromeTabsByGroupConfiguration = computed(() => {
const tabsByGroups = new Map<GroupConfiguration, chrome.tabs.Tab[]>()
const tabs = chromeState.tabs.items.value

for (const tab of tabs) {
const group = getGroupConfigurationForTab(tab)
if (!group) continue

if (tabsByGroups.has(group)) {
tabsByGroups.get(group)!.push(tab)
} else {
const groupTabs = [tab]
tabsByGroups.set(group, groupTabs)
}
}

return tabsByGroups
})

/**
* { [string: windowId]: Map<GroupConfiguration, chrome.tabs.Tab[]> }
*/
Expand Down Expand Up @@ -116,6 +97,13 @@ function getGroupConfigurationForTab(tab: chrome.tabs.Tab) {

const groupCreationTracker = new GroupCreationTracker()

function hasEnoughTabsToGroup(
group: GroupConfiguration,
tabs: chrome.tabs.Tab[],
) {
return tabs.length >= group.options.minTabsToGroup
}

async function assignTabsToGroup(
tabs: chrome.tabs.Tab[],
group: GroupConfiguration,
Expand All @@ -126,9 +114,10 @@ async function assignTabsToGroup(
tab.splitViewId === undefined ||
tab.splitViewId === chrome.tabs.SPLIT_VIEW_ID_NONE,
)

if (tabs.length === 0) return

if (!hasEnoughTabsToGroup(group, tabs)) return

const windowId = tabs[0].windowId

const tabGroupPredicate = createGroupConfigurationMatcher(group)
Expand All @@ -141,6 +130,7 @@ async function assignTabsToGroup(

// Before attempting a merge: Check whether the source and target windows are compatible to move tabs between them
let shouldMerge = false

if (group.options.merge) {
const sourceWindow = chromeState.windows.items.value.find(
window => window.id === windowId,
Expand Down Expand Up @@ -322,6 +312,8 @@ async function groupAllAppropriateTabs() {
tabsByGroups,
} of chromeTabsByWindowIdAndGroupConfiguration.value) {
for (const [group, tabs] of tabsByGroups) {
if (!hasEnoughTabsToGroup(group, tabs)) continue

for (const tab of tabs) {
assignedTabIds.add(tab.id!)
}
Expand Down Expand Up @@ -617,6 +609,8 @@ when(groupConfigurations.loaded)
console.debug('Waiting for extension state to initialize...')
await when(chromeState.tabs.loaded)

console.debug('groupConfigurations', groupConfigurations)

console.debug(
'Extension state initialized, grouping all appropriate tabs now...',
)
Expand Down Expand Up @@ -679,12 +673,20 @@ when(groupConfigurations.loaded)
// by moving a tab.
const updatedTab = await chrome.tabs.get(update.tab.id!)

const matchingGroupsInWindow =
chromeTabsByWindowIdAndGroupConfiguration.value.find(
({ windowId }) => windowId === updatedTab.windowId,
)?.tabsByGroups

let assignedAny = false
for (const [group, tabs] of chromeTabsByGroupConfiguration.value) {
for (const [group, tabs] of matchingGroupsInWindow ?? []) {
if (!tabs.some(tab => tab.id === updatedTab.id)) continue

if (!hasEnoughTabsToGroup(group, tabs)) break

assignedAny = true
await assignTabsToGroup([updatedTab], group)
await assignTabsToGroup(tabs, group)
break
}

// Check if tab has been reassigned,
Expand Down
13 changes: 13 additions & 0 deletions src/components/Dialog/EditDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const props = withDefaults(
options: () => ({
strict: false,
merge: false,
minTabsToGroup: 2,
}),
},
)
Expand All @@ -64,6 +65,7 @@ const editTitleLazy = ref(editTitle.value)
const editColor = ref(props.color)
const editStrict = ref(props.options.strict)
const editMerge = ref(props.options.merge)
const editMinTabsToGroup = ref(props.options.minTabsToGroup);
const editFieldBlurred = ref(false)

const colorMenu = ref()
Expand All @@ -88,6 +90,7 @@ watch(
editColor.value = props.color
editStrict.value = props.options.strict
editMerge.value = props.options.merge
editMinTabsToGroup.value = props.options.minTabsToGroup;
editFieldBlurred.value = false

await nextTick()
Expand Down Expand Up @@ -139,6 +142,7 @@ function save(event: KeyboardEvent) {
emit('save', editTitle.value, editColor.value, {
strict: editStrict.value,
merge: editMerge.value,
minTabsToGroup: editMinTabsToGroup.value,
})
show.value = false
}
Expand Down Expand Up @@ -203,6 +207,15 @@ function remove() {

<SlideVertical :duration="0.3">
<Card v-if="showAdvanced" seamless>
<CardSection ghost tight collapse seamless class="radio-container">
<v-text-field
v-model.number="editMinTabsToGroup"
type="number"
min="1"
label="Minimum tabs before grouping"
/>
</CardSection>

<CardSection ghost tight collapse seamless class="radio-container">
<v-checkbox id="edit-dialog-strict" v-model="editStrict" />
<ToggleLabel for="edit-dialog-strict">
Expand Down
2 changes: 1 addition & 1 deletion src/components/Popup/GroupSelection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async function addFromCurrent() {
title: tabGroup.value!.title ?? '',
color: tabGroup.value!.color,
matchers: [],
options: { strict: false, merge: false },
options: { strict: false, merge: false, minTabsToGroup: 2 },
},
])
await groupsChanged
Expand Down
2 changes: 1 addition & 1 deletion src/test/browser/options/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ test('Test group creation flow', async ({ page }) => {
title: 'Test Group',
color: 'blue',
matchers: [],
options: { strict: true, merge: true },
options: { strict: true, merge: true, minTabsToGroup: 2 },
},
])
})
6 changes: 3 additions & 3 deletions src/test/browser/options/edit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test.beforeEach(async ({ page }) => {
title: 'Test Group',
color: 'blue',
matchers: [],
options: { strict: true, merge: true },
options: { strict: true, merge: true, minTabsToGroup: 2 },
} as GroupConfigurationWithoutId,
])

Expand Down Expand Up @@ -105,7 +105,7 @@ test('Edit and save groups', async ({ page }) => {
title: 'Edited Group',
color: 'red',
matchers: [],
options: { strict: false, merge: false },
options: { strict: false, merge: false, minTabsToGroup: 2 },
},
])
})
Expand Down Expand Up @@ -136,7 +136,7 @@ test('Delete Groups and undo deletion', async ({ page }) => {
title: 'Test Group',
color: 'blue',
matchers: [],
options: { strict: true, merge: true },
options: { strict: true, merge: true, minTabsToGroup: 2 },
},
])
})
6 changes: 3 additions & 3 deletions src/test/browser/options/sort.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ test('Drag and drop groups', async ({ page }) => {
title: 'Test Group 1',
color: 'blue',
matchers: [],
options: { strict: true, merge: false },
options: { strict: true, merge: false, minTabsToGroup: 2 },
}
const group2 = {
title: 'Test Group 2',
color: 'red',
matchers: ['example.com', 'example.org'],
options: { strict: true, merge: false },
options: { strict: true, merge: false, minTabsToGroup: 2 },
}
const group3 = {
title: 'Test Group 3',
color: 'green',
matchers: ['github.com'],
options: { strict: true, merge: false },
options: { strict: true, merge: false, minTabsToGroup: 2 },
}

// Define groups programmatically
Expand Down
2 changes: 1 addition & 1 deletion src/test/browser/options/url-patterns.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ test.beforeEach(async ({ page }) => {
title: 'Test Group',
color: 'blue',
matchers: [],
options: { strict: true, merge: false },
options: { strict: true, merge: false, minTabsToGroup: 2 },
} as GroupConfigurationWithoutId,
])

Expand Down
1 change: 1 addition & 0 deletions src/util/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { colors } from './resources'
export const SaveOptionsSchema = z.object({
strict: z.boolean().default(false),
merge: z.boolean().default(false),
minTabsToGroup: z.number().int().positive().default(2),
})

const matcherPatternRegex = new RegExp(matcherPattern)
Expand Down