Move settings button back to the right in repo and org header
This will move the settings button back to the right, like known from older versions. For this, the overflow-menu was changed when a setting button is available. If no settings button is available, the behavior will not change. Fixes #3301 (cherry picked from commit f9628f883df485af1c208345d55a956db741eb76)
This commit is contained in:
parent
6a3b0d1fc8
commit
5f5d66624e
4 changed files with 141 additions and 5 deletions
|
@ -40,7 +40,7 @@
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .IsOrganizationOwner}}
|
{{if .IsOrganizationOwner}}
|
||||||
<a class="{{if .PageIsOrgSettings}}active {{end}}item" href="{{.OrgLink}}/settings">
|
<a id="settings-btn" class="{{if .PageIsOrgSettings}}active {{end}}right item" href="{{.OrgLink}}/settings">
|
||||||
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
|
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -177,18 +177,18 @@
|
||||||
{{$highlightSettings := true}}
|
{{$highlightSettings := true}}
|
||||||
{{if and .SignedUser.EnableRepoUnitHints (not (.Repository.AllUnitsEnabled ctx))}}
|
{{if and .SignedUser.EnableRepoUnitHints (not (.Repository.AllUnitsEnabled ctx))}}
|
||||||
{{$highlightSettings = false}}
|
{{$highlightSettings = false}}
|
||||||
<a class="{{if .PageIsRepoSettingsUnits}}active {{end}}item" href="{{.RepoLink}}/settings/units">
|
<a id="settings-btn" class="{{if .PageIsRepoSettingsUnits}}active {{end}}right item" href="{{.RepoLink}}/settings/units">
|
||||||
{{svg "octicon-diff-added"}} {{ctx.Locale.Tr "repo.settings.units.add_more"}}
|
{{svg "octicon-diff-added"}} {{ctx.Locale.Tr "repo.settings.units.add_more"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="{{if and .PageIsRepoSettings (or $highlightSettings (not .PageIsRepoSettingsUnits))}}active {{end}} item" href="{{.RepoLink}}/settings">
|
<a id="settings-btn" class="{{if and .PageIsRepoSettings (or $highlightSettings (not .PageIsRepoSettingsUnits))}}active {{end}}right item" href="{{.RepoLink}}/settings">
|
||||||
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
|
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{else if .Permission.IsAdmin}}
|
{{else if .Permission.IsAdmin}}
|
||||||
<div class="overflow-menu-items">
|
<div class="overflow-menu-items">
|
||||||
<a class="{{if .PageIsRepoSettings}}active {{end}} item" href="{{.RepoLink}}/settings">
|
<a id="settings-btn" class="{{if .PageIsRepoSettings}}active {{end}}right item" href="{{.RepoLink}}/settings">
|
||||||
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
|
{{svg "octicon-tools"}} {{ctx.Locale.Tr "repo.settings"}}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
114
tests/e2e/right-settings-button.test.e2e.js
Normal file
114
tests/e2e/right-settings-button.test.e2e.js
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
// @ts-check
|
||||||
|
import {test, expect} from '@playwright/test';
|
||||||
|
import {login_user, load_logged_in_context} from './utils_e2e.js';
|
||||||
|
|
||||||
|
test.beforeAll(async ({browser}, workerInfo) => {
|
||||||
|
await login_user(browser, workerInfo, 'user2');
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('desktop viewport', () => {
|
||||||
|
test.use({viewport: {width: 1920, height: 300}});
|
||||||
|
|
||||||
|
test('Settings button on right of repo header', async ({browser}, workerInfo) => {
|
||||||
|
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||||
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
await page.goto('/user2/repo1');
|
||||||
|
|
||||||
|
const settingsBtn = page.locator('.overflow-menu-items>#settings-btn');
|
||||||
|
await expect(settingsBtn).toBeVisible();
|
||||||
|
await expect(settingsBtn).toHaveClass(/right/);
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-button')).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Settings button on right of org header', async ({browser}, workerInfo) => {
|
||||||
|
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||||
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
await page.goto('/org3');
|
||||||
|
|
||||||
|
const settingsBtn = page.locator('.overflow-menu-items>#settings-btn');
|
||||||
|
await expect(settingsBtn).toBeVisible();
|
||||||
|
await expect(settingsBtn).toHaveClass(/right/);
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-button')).toHaveCount(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('User overview overflow menu should not be influenced', async ({page}) => {
|
||||||
|
await page.goto('/user2');
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-items>#settings-btn')).toHaveCount(0);
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-button')).toHaveCount(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('small viewport', () => {
|
||||||
|
test.use({viewport: {width: 800, height: 300}});
|
||||||
|
|
||||||
|
test('Settings button in overflow menu of repo header', async ({browser}, workerInfo) => {
|
||||||
|
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||||
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
await page.goto('/user2/repo1');
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-items>#settings-btn')).toHaveCount(0);
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-button')).toBeVisible();
|
||||||
|
|
||||||
|
await page.click('.overflow-menu-button');
|
||||||
|
await expect(page.locator('.tippy-target>#settings-btn')).toBeVisible();
|
||||||
|
|
||||||
|
// Verify that we have no duplicated items
|
||||||
|
const shownItems = await page.locator('.overflow-menu-items>a').all();
|
||||||
|
expect(shownItems).not.toHaveLength(0);
|
||||||
|
const overflowItems = await page.locator('.tippy-target>a').all();
|
||||||
|
expect(overflowItems).not.toHaveLength(0);
|
||||||
|
|
||||||
|
const items = shownItems.concat(overflowItems);
|
||||||
|
expect(Array.from(new Set(items))).toHaveLength(items.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Settings button in overflow menu of org header', async ({browser}, workerInfo) => {
|
||||||
|
const context = await load_logged_in_context(browser, workerInfo, 'user2');
|
||||||
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
await page.goto('/org3');
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-items>#settings-btn')).toHaveCount(0);
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-button')).toBeVisible();
|
||||||
|
|
||||||
|
await page.click('.overflow-menu-button');
|
||||||
|
await expect(page.locator('.tippy-target>#settings-btn')).toBeVisible();
|
||||||
|
|
||||||
|
// Verify that we have no duplicated items
|
||||||
|
const shownItems = await page.locator('.overflow-menu-items>a').all();
|
||||||
|
expect(shownItems).not.toHaveLength(0);
|
||||||
|
const overflowItems = await page.locator('.tippy-target>a').all();
|
||||||
|
expect(overflowItems).not.toHaveLength(0);
|
||||||
|
|
||||||
|
const items = shownItems.concat(overflowItems);
|
||||||
|
expect(Array.from(new Set(items))).toHaveLength(items.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('User overview overflow menu should not be influenced', async ({page}) => {
|
||||||
|
await page.goto('/user2');
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-items>#settings-btn')).toHaveCount(0);
|
||||||
|
|
||||||
|
await expect(page.locator('.overflow-menu-button')).toBeVisible();
|
||||||
|
await page.click('.overflow-menu-button');
|
||||||
|
await expect(page.locator('.tippy-target>#settings-btn')).toHaveCount(0);
|
||||||
|
|
||||||
|
// Verify that we have no duplicated items
|
||||||
|
const shownItems = await page.locator('.overflow-menu-items>a').all();
|
||||||
|
expect(shownItems).not.toHaveLength(0);
|
||||||
|
const overflowItems = await page.locator('.tippy-target>a').all();
|
||||||
|
expect(overflowItems).not.toHaveLength(0);
|
||||||
|
|
||||||
|
const items = shownItems.concat(overflowItems);
|
||||||
|
expect(Array.from(new Set(items))).toHaveLength(items.length);
|
||||||
|
});
|
||||||
|
});
|
|
@ -69,13 +69,35 @@ window.customElements.define('overflow-menu', class extends HTMLElement {
|
||||||
this.tippyItems = [];
|
this.tippyItems = [];
|
||||||
const menuRight = this.offsetLeft + this.offsetWidth;
|
const menuRight = this.offsetLeft + this.offsetWidth;
|
||||||
const menuItems = this.menuItemsEl.querySelectorAll('.item');
|
const menuItems = this.menuItemsEl.querySelectorAll('.item');
|
||||||
|
const settingItem = this.menuItemsEl.querySelector('#settings-btn');
|
||||||
for (const item of menuItems) {
|
for (const item of menuItems) {
|
||||||
const itemRight = item.offsetLeft + item.offsetWidth;
|
const itemRight = item.offsetLeft + item.offsetWidth;
|
||||||
if (menuRight - itemRight < 38) { // roughly the width of .overflow-menu-button
|
// Width of the settings button plus a small value to get the next item to the left if there is directly one
|
||||||
|
// If no setting button is in the menu the default threshold is 38 - roughly the width of .overflow-menu-button
|
||||||
|
const overflowBtnThreshold = 38;
|
||||||
|
const threshold = settingItem?.offsetWidth ?? overflowBtnThreshold;
|
||||||
|
// If we have a settings item on the right-hand side, we must also check if the first,
|
||||||
|
// possibly overflowing item would still fit on the left-hand side of the overflow menu
|
||||||
|
// If not, it must be added to the array (twice). The duplicate is removed with the shift.
|
||||||
|
if (settingItem && !this.tippyItems?.length && item !== settingItem && menuRight - itemRight < overflowBtnThreshold) {
|
||||||
|
this.tippyItems.push(settingItem);
|
||||||
|
}
|
||||||
|
if (menuRight - itemRight < threshold) {
|
||||||
this.tippyItems.push(item);
|
this.tippyItems.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special handling for settings button on right. Only done if a setting item is present
|
||||||
|
if (settingItem) {
|
||||||
|
// If less than 2 items overflow, remove all items (only settings "overflowed" - because it's on the right side)
|
||||||
|
if (this.tippyItems?.length < 2) {
|
||||||
|
this.tippyItems = [];
|
||||||
|
} else {
|
||||||
|
// Remove the first item of the list, because we have always one item more in the array due to the big threshold above
|
||||||
|
this.tippyItems.shift();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if there are no overflown items, remove any previously created button
|
// if there are no overflown items, remove any previously created button
|
||||||
if (!this.tippyItems?.length) {
|
if (!this.tippyItems?.length) {
|
||||||
const btn = this.querySelector('.overflow-menu-button');
|
const btn = this.querySelector('.overflow-menu-button');
|
||||||
|
|
Loading…
Reference in a new issue