diff --git a/.github/workflows/lint_openapi_schema.yml b/.github/workflows/lint_openapi_schema.yml index 464d1cef825f..4269db840770 100644 --- a/.github/workflows/lint_openapi_schema.yml +++ b/.github/workflows/lint_openapi_schema.yml @@ -28,6 +28,11 @@ jobs: - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - uses: actions/setup-node@v4 + with: + node-version: '18.12.1' + cache: 'yarn' + cache-dependency-path: 'galaxy root/client/yarn.lock' - name: Get full Python version id: full-python-version shell: bash diff --git a/SECURITY.md b/SECURITY.md index 2b30ab9b1106..c1dcb56f30e9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,8 +16,7 @@ The following branches or releases receive security support: - Development on the `dev` branch, hosted on GitHub, which will become the next release of Galaxy - Releases within the past 12 months. - - E.g. 16.04 will receive support until 2017-04. As the month changes to 2017-05 it will become unsupported. -- There are currently no plans for Long Term Support (LTS) releases. + - E.g. 24.0 will receive support for a full year, at which point 25.0 will be available. For unsupported branches: diff --git a/client/src/api/index.test.ts b/client/src/api/index.test.ts index 42b666b2f03f..fb16bc95edc2 100644 --- a/client/src/api/index.test.ts +++ b/client/src/api/index.test.ts @@ -22,6 +22,7 @@ const REGISTERED_USER: User = { const ANONYMOUS_USER: AnonymousUser = { isAnonymous: true, + total_disk_usage: 0, }; const SESSIONLESS_USER = null; diff --git a/client/src/api/index.ts b/client/src/api/index.ts index d1dbc8854bbb..718fa099a45a 100644 --- a/client/src/api/index.ts +++ b/client/src/api/index.ts @@ -227,7 +227,7 @@ export interface User extends QuotaUsageResponse { username?: string; } -export interface AnonymousUser { +export interface AnonymousUser extends QuotaUsageResponse { id?: string; isAnonymous: true; is_admin?: false; diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index a8d706bbdfae..2db6faeb1963 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -6155,6 +6155,8 @@ export interface components { * @enum {string} */ model_class: "HistoryDatasetAssociation"; + /** Purged */ + purged: boolean; /** * State * @description The current state of this dataset. diff --git a/client/src/components/AboutGalaxy.vue b/client/src/components/AboutGalaxy.vue index 4c40f4978d06..8dad39ed35b1 100644 --- a/client/src/components/AboutGalaxy.vue +++ b/client/src/components/AboutGalaxy.vue @@ -3,6 +3,7 @@ /* (injected by webpack) */ import { computed } from "vue"; +import { RouterLink } from "vue-router"; import { useConfig } from "@/composables/config"; import { getAppRoot } from "@/onload/loadConfig"; @@ -28,47 +29,88 @@ const versionUserDocumentationUrl = computed(() => { diff --git a/client/src/components/ActivityBar/ActivityBar.vue b/client/src/components/ActivityBar/ActivityBar.vue index 0d9f83fb3d05..cde4d7b190ad 100644 --- a/client/src/components/ActivityBar/ActivityBar.vue +++ b/client/src/components/ActivityBar/ActivityBar.vue @@ -179,11 +179,7 @@ watch( :to="activity.to" @click="onToggleSidebar()" /> { it("availability of built-in activities", async () => { const items = wrapper.findAll(activityItemSelector); - expect(items.length).toBe(Activities.length); + const nOptional = Activities.filter((x) => x.optional).length; + expect(items.length).toBe(nOptional); }); - it("visible but non-optional activity", async () => { + it("visible and optional activity", async () => { activityStore.setAll([testActivity("1")]); await wrapper.vm.$nextTick(); const items = wrapper.findAll(activityItemSelector); expect(items.length).toBe(1); - const pinnedCheckbox = items.at(0).find("[data-icon='thumbtack']"); - expect(pinnedCheckbox.exists()).toBeTruthy(); - const pinnedIcon = wrapper.find("[icon='activity-test-icon'"); - expect(pinnedIcon.exists()).toBeTruthy(); + const checkbox = items.at(0).find("[title='Hide in Activity Bar']"); + expect(checkbox.exists()).toBeTruthy(); + const icon = wrapper.find("[icon='activity-test-icon'"); + expect(icon.exists()).toBeTruthy(); expect(activityStore.getAll()[0].visible).toBeTruthy(); - pinnedCheckbox.trigger("click"); + checkbox.trigger("click"); await wrapper.vm.$nextTick(); - expect(activityStore.getAll()[0].visible).toBeTruthy(); + expect(activityStore.getAll()[0].visible).toBeFalsy(); }); it("non-visible but optional activity", async () => { @@ -84,12 +85,12 @@ describe("ActivitySettings", () => { await wrapper.vm.$nextTick(); const items = wrapper.findAll(activityItemSelector); expect(items.length).toBe(1); - const hiddenCheckbox = items.at(0).find("[data-icon='square']"); - expect(hiddenCheckbox.exists()).toBeTruthy(); + const checkbox = items.at(0).find("[title='Show in Activity Bar']"); + expect(checkbox.exists()).toBeTruthy(); expect(activityStore.getAll()[0].visible).toBeFalsy(); - hiddenCheckbox.trigger("click"); + checkbox.trigger("click"); await wrapper.vm.$nextTick(); - const visibleCheckbox = items.at(0).find("[data-icon='check-square']"); + const visibleCheckbox = items.at(0).find("[title='Hide in Activity Bar']"); expect(visibleCheckbox.exists()).toBeTruthy(); expect(activityStore.getAll()[0].visible).toBeTruthy(); }); diff --git a/client/src/components/ActivityBar/ActivitySettings.vue b/client/src/components/ActivityBar/ActivitySettings.vue index 835691d3c0b3..fe2ecce28dd5 100644 --- a/client/src/components/ActivityBar/ActivitySettings.vue +++ b/client/src/components/ActivityBar/ActivitySettings.vue @@ -1,16 +1,19 @@ @@ -104,47 +72,79 @@ onMounted(() => { logo logo - + {{ brand }} - + - + v-if="windowTab" + :id="windowTab.id" + :icon="windowTab.icon" + :toggle="windowToggle" + :tooltip="windowTab.tooltip" + @click="onWindowToggle" /> - - - - + :title="tab.title" + :icon="tab.icon" + :url="tab.url" + :tooltip="tab.tooltip" + :target="tab.target" + @click="tab.onclick ? tab.onclick : undefined" /> + + + + + - + @@ -180,16 +180,18 @@ onMounted(() => { cursor: pointer; text-decoration: none; color: var(--masthead-text-color); + margin-right: 0.25rem; + margin-left: 0.25rem; &:hover { color: var(--masthead-text-hover); } &.nav-icon { - font-size: 1.3em; + font-size: 1.2em; .nav-note { position: absolute; - left: 1.9rem; - top: 1.9rem; - font-size: 0.6rem; + left: 1.6rem; + top: 1.6rem; + font-size: 0.4rem; font-weight: bold; } } @@ -201,11 +203,12 @@ onMounted(() => { } .navbar-brand { cursor: pointer; + line-height: $masthead-height; img { filter: $text-shadow; display: inline; border: none; - height: 2.3rem; + height: 2rem; } } .navbar-text { @@ -213,7 +216,7 @@ onMounted(() => { font-weight: bold; font-family: Verdana, sans-serif; font-size: 1rem; - line-height: 2rem; + line-height: $masthead-height; color: var(--masthead-text-color); } } diff --git a/client/src/components/Masthead/MastheadDropdown.vue b/client/src/components/Masthead/MastheadDropdown.vue new file mode 100644 index 000000000000..02bd10771694 --- /dev/null +++ b/client/src/components/Masthead/MastheadDropdown.vue @@ -0,0 +1,48 @@ + + + diff --git a/client/src/components/Masthead/MastheadItem.test.js b/client/src/components/Masthead/MastheadItem.test.js deleted file mode 100644 index 68e8780c00c0..000000000000 --- a/client/src/components/Masthead/MastheadItem.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import { mount } from "@vue/test-utils"; -import { getLocalVue } from "tests/jest/helpers"; - -import MastheadItem from "./MastheadItem.vue"; - -describe("MastheadItem.vue", () => { - let wrapper; - let localVue; - - beforeEach(() => { - localVue = getLocalVue(); - }); - - function m(active, menu) { - const tab = { - id: "mytab", - menu: menu, - }; - - return mount(MastheadItem, { - propsData: { - tab, - activeTab: active, - }, - localVue, - }); - } - - it("should render active tab with menus", async () => { - wrapper = m("mytab", true); - expect(wrapper.classes("active")).toBe(true); - expect(wrapper.classes("b-nav-dropdown")).toBe(true); - }); - - it("should render inactive tabs without menus", async () => { - wrapper = m("othertab", false); - expect(wrapper.classes("active")).toBe(false); - expect(wrapper.classes("b-nav-dropdown")).toBe(false); - }); -}); diff --git a/client/src/components/Masthead/MastheadItem.vue b/client/src/components/Masthead/MastheadItem.vue index 889526e01ffa..f3c1ca5c3ab5 100644 --- a/client/src/components/Masthead/MastheadItem.vue +++ b/client/src/components/Masthead/MastheadItem.vue @@ -1,125 +1,57 @@