Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 2.11.0-privacyPolicy
  • APIv2
  • Docs/Setup
  • Experiment/fix-debugging
  • Experimental/Heinrichs-cypress
  • Feature/xxxx-turnOffDataPub
  • Fix/xxxx-ToS400Error
  • Fix/xxxx-migrateLogin
  • Fix/xxxx-tokenUploadButton
  • Hotfix/0038-correctDownload
  • Hotfix/1917-PublicFilesVisibility
  • Hotfix/1963-fixOrganizationField
  • Hotfix/2015-PublicFilesVisibility
  • Hotfix/2130-uiv2ContactChange
  • Hotfix/2144-invitationCall
  • Hotfix/2150-fixUpload
  • Hotfix/2160-userOrgsInst
  • Hotfix/2190-requiredFieldsForUserProfile
  • Hotfix/2196-RCVTableTranslation
  • Hotfix/2212-fixFiles
  • Hotfix/2226-userProfileSaveButton
  • Hotfix/2232-dependencyFix
  • Hotfix/2233-fixMe
  • Hotfix/2258-saveButtonWorksAsExpected
  • Hotfix/2296-selectedValuesNotReturned
  • Hotfix/2308-defaultLicense
  • Hotfix/2335-fixingSearchRCV
  • Hotfix/2353-dropShape
  • Hotfix/2370-fixDeleteButton
  • Hotfix/2378-linkedFix
  • Hotfix/2379-filesDragAndDrop
  • Hotfix/2382-guestStillBuggy
  • Hotfix/2384-guestsAndLinked
  • Hotfix/2427-adminTrouble
  • Hotfix/2459-EncodingPath
  • Hotfix/2465-orcidLink
  • Hotfix/2465-orcidLink-v1.25.1
  • Hotfix/2504-formGen
  • Hotfix/2541-resCreate
  • Hotfix/2601-correctMetadataIdentity
  • Hotfix/2611-feedback
  • Hotfix/2618-turtle
  • Hotfix/2681-validationErrors
  • Hotfix/2684-correctEncoding
  • Hotfix/2684-fixSubMetadata
  • Hotfix/2713-validateEntryName
  • Hotfix/2734-allowEmptyLicense
  • Hotfix/2765-encodingAgain
  • Hotfix/2852-adaptTextForToSUi
  • Hotfix/2853-optimizationV4
  • Hotfix/2943-reloadingResources
  • Hotfix/2943-searchHighlighting
  • Hotfix/2957-styleAndUpgrade
  • Hotfix/2971-fixTextInDataPub
  • Hotfix/2989-cookieLength
  • Hotfix/662-keepSidebarExpanded
  • Hotfix/xxxx-correctLinking
  • Hotfix/xxxx-folderRecursive
  • Hotfix/xxxx-fullscreenCss
  • Hotfix/xxxx-homepageDisplay
  • Hotfix/xxxx-liveReleaseFixes
  • Hotfix/xxxx-partnerProjects
  • Hotfix/xxxx-workingFileIndex
  • Issue/1782-structualDataIntegration
  • Issue/1792-newMetadataStructure
  • Issue/1822-coscineUIv2App
  • Issue/1824-componentsUIv2
  • Issue/1824-routerAdditions
  • Issue/1825-codeQualityPipelines
  • Issue/1833-newLogin
  • Issue/1843-multipleFilesValidation
  • Issue/1860-searchScoping
  • Issue/1861-searchMetadata
  • Issue/1862-searchFacets
  • Issue/1863-paginationForSearch
  • Issue/1926-userProfile
  • Issue/1927-projectAppMigration
  • Issue/1928-sidebarmenuAddition
  • Issue/1929-vuexToPinia
  • Issue/1938-internalHandling
  • Issue/1951-quotaImplementation
  • Issue/1953-owlImports
  • Issue/1957-resourceAppMigration
  • Issue/1957-resourceAppMigrationNew
  • Issue/1962-SearchAppUI2
  • Issue/1964-tokenExpiryUIv2
  • Issue/1965-userListMigration
  • Issue/1970-breadcrumbs
  • Issue/1971-projectEditCreateMigration
  • Issue/1972-homeDepot
  • Issue/1974-shibbolethLogout
  • Issue/1976-resouceCreationVaildEmail
  • Issue/1979-supportAdminUIv2Migration
  • Issue/1980-userManagement
  • Issue/1985-adaptSidebar
  • Issue/2002-migrateResourceCreate
  • Issue/2003-resourceSettings
  • Issue/2008-quotaManagement
  • Issue/2011-pathConfig
  • Issue/2016-BannerMigration
  • 1.28.0-pilot
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.10.3
  • v1.11.0
  • v1.11.1
  • v1.11.2
  • v1.11.3
  • v1.11.4
  • v1.11.5
  • v1.11.6
  • v1.11.7
  • v1.12.0
  • v1.13.0
  • v1.14.0
  • v1.14.1
  • v1.14.2
  • v1.14.3
  • v1.15.0
  • v1.15.1
  • v1.16.0
  • v1.16.1
  • v1.16.2
  • v1.16.3
  • v1.17.0
  • v1.17.1
  • v1.17.2
  • v1.18.0
  • v1.18.1
  • v1.19.0
  • v1.2.0
  • v1.20.0
  • v1.20.1
  • v1.20.2
  • v1.20.3
  • v1.20.4
  • v1.20.5
  • v1.21.0
  • v1.22.0
  • v1.22.1
  • v1.22.2
  • v1.23.0
  • v1.23.1
  • v1.23.2
  • v1.23.3
  • v1.23.4
  • v1.23.5
  • v1.23.6
  • v1.23.6-patch-2417-2427
  • v1.24.0
  • v1.24.1
  • v1.25.0
  • v1.25.1
  • v1.26.0
  • v1.26.1
  • v1.27.0
  • v1.27.1
  • v1.27.1-pilot
  • v1.28.0
  • v1.29.0
  • v1.29.1
  • v1.29.2
  • v1.3.0
  • v1.30.0
  • v1.30.1
  • v1.30.2
  • v1.31.0
  • v1.32.0
  • v1.4.0
  • v1.4.1
  • v1.5.0
  • v1.6.0
  • v1.6.1
  • v1.6.2
  • v1.7.0
  • v1.8.0
  • v1.8.1
  • v1.8.2
  • v1.9.0
  • v2.0.0
  • v2.1.0
  • v2.10.0
  • v2.10.1
  • v2.11.0
  • v2.12.0
  • v2.12.1
  • v2.12.2
  • v2.12.3
  • v2.12.4
  • v2.12.5
  • v2.13.0
  • v2.13.1
  • v2.13.2
  • v2.13.3
  • v2.13.4
  • v2.14.0
  • v2.15.0
200 results

Target

Select target project
  • coscine/frontend/apps/ui
1 result
Select Git revision
  • 2.11.0-privacyPolicy
  • APIv2
  • Docs/Setup
  • Experiment/fix-debugging
  • Experimental/Heinrichs-cypress
  • Feature/xxxx-turnOffDataPub
  • Fix/xxxx-ToS400Error
  • Fix/xxxx-migrateLogin
  • Fix/xxxx-tokenUploadButton
  • Hotfix/0038-correctDownload
  • Hotfix/1917-PublicFilesVisibility
  • Hotfix/1963-fixOrganizationField
  • Hotfix/2015-PublicFilesVisibility
  • Hotfix/2130-uiv2ContactChange
  • Hotfix/2144-invitationCall
  • Hotfix/2150-fixUpload
  • Hotfix/2160-userOrgsInst
  • Hotfix/2190-requiredFieldsForUserProfile
  • Hotfix/2196-RCVTableTranslation
  • Hotfix/2212-fixFiles
  • Hotfix/2226-userProfileSaveButton
  • Hotfix/2232-dependencyFix
  • Hotfix/2233-fixMe
  • Hotfix/2258-saveButtonWorksAsExpected
  • Hotfix/2296-selectedValuesNotReturned
  • Hotfix/2308-defaultLicense
  • Hotfix/2335-fixingSearchRCV
  • Hotfix/2353-dropShape
  • Hotfix/2370-fixDeleteButton
  • Hotfix/2378-linkedFix
  • Hotfix/2379-filesDragAndDrop
  • Hotfix/2382-guestStillBuggy
  • Hotfix/2384-guestsAndLinked
  • Hotfix/2427-adminTrouble
  • Hotfix/2459-EncodingPath
  • Hotfix/2465-orcidLink
  • Hotfix/2465-orcidLink-v1.25.1
  • Hotfix/2504-formGen
  • Hotfix/2541-resCreate
  • Hotfix/2601-correctMetadataIdentity
  • Hotfix/2611-feedback
  • Hotfix/2618-turtle
  • Hotfix/2681-validationErrors
  • Hotfix/2684-correctEncoding
  • Hotfix/2684-fixSubMetadata
  • Hotfix/2713-validateEntryName
  • Hotfix/2734-allowEmptyLicense
  • Hotfix/2765-encodingAgain
  • Hotfix/2852-adaptTextForToSUi
  • Hotfix/2853-optimizationV4
  • Hotfix/2943-reloadingResources
  • Hotfix/2943-searchHighlighting
  • Hotfix/2957-styleAndUpgrade
  • Hotfix/2971-fixTextInDataPub
  • Hotfix/2989-cookieLength
  • Hotfix/662-keepSidebarExpanded
  • Hotfix/xxxx-correctLinking
  • Hotfix/xxxx-folderRecursive
  • Hotfix/xxxx-fullscreenCss
  • Hotfix/xxxx-homepageDisplay
  • Hotfix/xxxx-liveReleaseFixes
  • Hotfix/xxxx-partnerProjects
  • Hotfix/xxxx-workingFileIndex
  • Issue/1782-structualDataIntegration
  • Issue/1792-newMetadataStructure
  • Issue/1822-coscineUIv2App
  • Issue/1824-componentsUIv2
  • Issue/1824-routerAdditions
  • Issue/1825-codeQualityPipelines
  • Issue/1833-newLogin
  • Issue/1843-multipleFilesValidation
  • Issue/1860-searchScoping
  • Issue/1861-searchMetadata
  • Issue/1862-searchFacets
  • Issue/1863-paginationForSearch
  • Issue/1926-userProfile
  • Issue/1927-projectAppMigration
  • Issue/1928-sidebarmenuAddition
  • Issue/1929-vuexToPinia
  • Issue/1938-internalHandling
  • Issue/1951-quotaImplementation
  • Issue/1953-owlImports
  • Issue/1957-resourceAppMigration
  • Issue/1957-resourceAppMigrationNew
  • Issue/1962-SearchAppUI2
  • Issue/1964-tokenExpiryUIv2
  • Issue/1965-userListMigration
  • Issue/1970-breadcrumbs
  • Issue/1971-projectEditCreateMigration
  • Issue/1972-homeDepot
  • Issue/1974-shibbolethLogout
  • Issue/1976-resouceCreationVaildEmail
  • Issue/1979-supportAdminUIv2Migration
  • Issue/1980-userManagement
  • Issue/1985-adaptSidebar
  • Issue/2002-migrateResourceCreate
  • Issue/2003-resourceSettings
  • Issue/2008-quotaManagement
  • Issue/2011-pathConfig
  • Issue/2016-BannerMigration
  • 1.28.0-pilot
  • v1.0.0
  • v1.1.0
  • v1.10.0
  • v1.10.1
  • v1.10.2
  • v1.10.3
  • v1.11.0
  • v1.11.1
  • v1.11.2
  • v1.11.3
  • v1.11.4
  • v1.11.5
  • v1.11.6
  • v1.11.7
  • v1.12.0
  • v1.13.0
  • v1.14.0
  • v1.14.1
  • v1.14.2
  • v1.14.3
  • v1.15.0
  • v1.15.1
  • v1.16.0
  • v1.16.1
  • v1.16.2
  • v1.16.3
  • v1.17.0
  • v1.17.1
  • v1.17.2
  • v1.18.0
  • v1.18.1
  • v1.19.0
  • v1.2.0
  • v1.20.0
  • v1.20.1
  • v1.20.2
  • v1.20.3
  • v1.20.4
  • v1.20.5
  • v1.21.0
  • v1.22.0
  • v1.22.1
  • v1.22.2
  • v1.23.0
  • v1.23.1
  • v1.23.2
  • v1.23.3
  • v1.23.4
  • v1.23.5
  • v1.23.6
  • v1.23.6-patch-2417-2427
  • v1.24.0
  • v1.24.1
  • v1.25.0
  • v1.25.1
  • v1.26.0
  • v1.26.1
  • v1.27.0
  • v1.27.1
  • v1.27.1-pilot
  • v1.28.0
  • v1.29.0
  • v1.29.1
  • v1.29.2
  • v1.3.0
  • v1.30.0
  • v1.30.1
  • v1.30.2
  • v1.31.0
  • v1.32.0
  • v1.4.0
  • v1.4.1
  • v1.5.0
  • v1.6.0
  • v1.6.1
  • v1.6.2
  • v1.7.0
  • v1.8.0
  • v1.8.1
  • v1.8.2
  • v1.9.0
  • v2.0.0
  • v2.1.0
  • v2.10.0
  • v2.10.1
  • v2.11.0
  • v2.12.0
  • v2.12.1
  • v2.12.2
  • v2.12.3
  • v2.12.4
  • v2.12.5
  • v2.13.0
  • v2.13.1
  • v2.13.2
  • v2.13.3
  • v2.13.4
  • v2.14.0
  • v2.15.0
200 results
Show changes
Commits on Source (19)
Showing
with 796 additions and 202 deletions
......@@ -26,6 +26,5 @@ module.exports = {
],
"@typescript-eslint/no-empty-interface": 1, // empty Interfaces will be only warnings for now.
"vue/multi-word-component-names": "off"
},
}
......@@ -6,11 +6,13 @@ declare module 'vue' {
export interface GlobalComponents {
BreadCrumbs: typeof import('./src/components/BreadCrumbs.vue')['default']
CoscineCard: typeof import('./src/components/CoscineCard.vue')['default']
CoscineDeleteModal: typeof import('./src/components/CoscineDeleteModal.vue')['default']
CoscineFormGroup: typeof import('./src/components/CoscineFormGroup.vue')['default']
CoscineHeadline: typeof import('./src/components/CoscineHeadline.vue')['default']
CoscineModal: typeof import('./src/components/CoscineModal.vue')['default']
DevFooter: typeof import('./src/components/DevFooter.vue')['default']
LoadingIndicator: typeof import('./src/components/LoadingIndicator.vue')['default']
LoadingSpinner: typeof import('./src/components/LoadingSpinner.vue')['default']
MultiSelect: typeof import('./src/components/MultiSelect.vue')['default']
Navbar: typeof import('./src/components/Navbar.vue')['default']
SidebarMenu: typeof import('./src/components/SidebarMenu.vue')['default']
......
{
"name": "ui",
"version": "1.3.0",
"version": "1.4.0",
"private": true,
"scripts": {
"dev": "vite",
......@@ -10,29 +10,30 @@
"lint:fix": "eslint './src/**/*.{js,ts,tsx,vue,md}' --fix"
},
"dependencies": {
"@coscine/api-client": "^1.3.0",
"@coscine/api-client": "^1.5.0",
"@vueuse/core": "^6.5.3",
"axios": "^0.25.0",
"axios": "^0.26.1",
"bootstrap": "^4.6.1",
"bootstrap-icons": "^1.8.1",
"bootstrap-vue": "^2.21.2",
"core-js": "^3.20.0",
"core-js": "^3.21.1",
"http-status-codes": "^2.2.0",
"jose": "^4.5.1",
"jose": "^4.6.0",
"jquery": "^3.6.0",
"lint-staged": "^12.1.2",
"lint-staged": "^12.3.5",
"lodash": "^4.17.21",
"moment": "^2.29.1",
"pinia": "^2.0.11",
"sass": "^1.45.0",
"semantic-release": "^18.0.1",
"pinia": "^2.0.12",
"sass": "^1.49.9",
"semantic-release": "^19.0.2",
"uuid": "^8.3.2",
"vite-aliases": "^0.8.7",
"vite-aliases": "^0.9.1",
"vue": "^2.6.14",
"vue-demi": "^0.12.1",
"vue-i18n": "^8.27.0",
"vue-multiselect": "^2.1.6",
"vue-router": "^3.5.3",
"vue-select": "^3.18.3",
"vue-sidebar-menu": "^4.8.1",
"vuelidate": "^0.7.7"
},
......@@ -44,27 +45,28 @@
"@semantic-release/release-notes-generator": "^10.0.3",
"@types/lodash": "^4.14.178",
"@types/uuid": "^8.3.4",
"@types/vue-select": "^3.16.0",
"@types/vuelidate": "^0.7.15",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"@typescript-eslint/eslint-plugin": "^5.15.0",
"@typescript-eslint/parser": "^5.15.0",
"@vue/cli-plugin-eslint": "^4.5.15",
"@vue/composition-api": "^1.4.5",
"@vue/eslint-config-prettier": "^6.0.0",
"@vue/eslint-config-typescript": "^8.0.0",
"conventional-changelog-eslint": "^3.0.9",
"eslint": "^8.6.0",
"eslint": "^8.11.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-functional": "^4.1.1",
"eslint-plugin-functional": "^4.2.0",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-vue": "^8.3.0",
"eslint-plugin-vue": "^8.5.0",
"prettier": "^2.5.1",
"typescript": "^4.5.4",
"unplugin-vue-components": "0.17.11",
"vite": "^2.8.0",
"vite": "^2.8.6",
"vite-plugin-vue2": "^1.9.3",
"vite-plugin-windicss": "^1.7.0",
"vite-plugin-windicss": "^1.8.3",
"vue-template-compiler": "^2.6.14"
},
"packageManager": "yarn@3.2.0"
......
......@@ -6,25 +6,25 @@
<div class="mr-0 d-flex">
<SidebarMenu class="mr-2" />
<div class="container-fluid mx-5">
<Pilot />
<Maintenance />
<BreadCrumbs />
<RouterView />
</div>
</div>
</main>
<ExpiryToast />
<!--DevFooter /-->
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue-demi";
import * as jose from "jose";
import moment from "moment";
// import the main store
import { useMainStore } from "@/store/index";
import { useProjectStore } from "@/modules/project/store";
import { useUserStore } from "@/modules/user/store";
import { useLoginStore } from "@/modules/login/store";
export default defineComponent({
setup() {
......@@ -39,12 +39,6 @@ export default defineComponent({
this.initialize();
},
data() {
return {
tokenExpiredInterval: 0,
};
},
computed: {
loading(): boolean {
return this.mainStore.coscine.loading.counter > 0;
......@@ -74,75 +68,7 @@ export default defineComponent({
await this.userStore.retrieveUser(this.loggedIn);
await this.projectStore.retrieveAllProjects();
this.userStore.setUserLanguagePreference();
if (this.userStore.user !== null) {
// Trigger token expiration check
this.tokenExpiredInterval = window.setInterval(
this.notifyTokenExpired,
this.checkTokenExpiration()
);
}
},
notifyTokenExpired() {
const h = this.$createElement;
// Create the toast's message
const message = h("p", { class: ["text-center"] }, [
this.$t("toast.session.message").toString(),
h("br"),
h("b-button", {
class: ["mt-2"],
attrs: {
size: "sm",
variant: "secondary",
},
// On button click, use router to redirect to login page
on: {
click: () => {
const loginStore = useLoginStore();
loginStore.redirectToLogin(this.$route, true);
},
},
domProps: {
innerHTML: this.$t("toast.session.link").toString(),
},
}),
]);
// Create the toast
this.$bvToast.toast([message], {
title: this.$t("toast.session.title").toString(),
toaster: "b-toaster-bottom-right",
variant: "danger",
solid: true,
noAutoHide: true,
noCloseButton: true,
appendToast: false,
});
// Cancel interval expiration check
clearInterval(this.tokenExpiredInterval);
},
checkTokenExpiration(): number {
const jwt = jose.decodeJwt(this.mainStore.coscine.authorization.bearer);
// Use UTC to avoid time conversion errors
const tokenExpiresAt = moment(jwt.exp! * 1000).utc();
const now = moment.utc(moment.now());
const untilTokenExpiration = moment.duration(tokenExpiresAt.diff(now));
console.debug(
"Access Token Expiration Overview:\n",
"\nNow (UTC): ",
now.format("LL HH:mm:ss"),
"\nIssued (UTC): ",
moment(jwt.iat! * 1000)
.utc()
.format("LL HH:mm:ss"),
"\nExpiry (UTC): ",
tokenExpiresAt.format("LL HH:mm:ss"),
"\nExpiration: ",
untilTokenExpiration.humanize(true)
);
// Return as milliseconds for setInterval() method
return untilTokenExpiration.asMilliseconds();
await this.mainStore.getMaintenance();
},
},
});
......
......@@ -10,9 +10,13 @@ declare module "vue" {
CoscineHeadline: typeof import("./components/CoscineHeadline.vue")["default"];
CoscineModal: typeof import("./components/CoscineModal.vue")["default"];
DevFooter: typeof import("./components/DevFooter.vue")["default"];
ExpiryToast: typeof import("./components/ExpiryToast.vue")["default"];
LoadingIndicator: typeof import("./components/LoadingIndicator.vue")["default"];
LoadingSpinner: typeof import("./components/LoadingSpinner.vue")["default"];
Maintenance: typeof import("./components/banner/Maintenance.vue")["default"];
MultiSelect: typeof import("./components/MultiSelect.vue")["default"];
Navbar: typeof import("./components/Navbar.vue")["default"];
Pilot: typeof import("./components/banner/Pilot.vue")["default"];
SidebarMenu: typeof import("./components/SidebarMenu.vue")["default"];
}
}
......
......@@ -57,9 +57,16 @@ export default defineComponent({
(path) =>
path.trim() !== "" && path.trim() !== "p" && path.trim() !== "r"
);
// Deal with Root Path inclusion
if (pathArray.length === 1) {
pathArray.unshift("");
}
let breadcrumbs = pathArray.reduce(
(breadcrumbArray: RouteLink[], path, idx) => {
console.log(this.$route.matched[idx]);
// Deal with Root Path inclusion
if (path === "") {
return breadcrumbArray;
}
breadcrumbArray.push({
to: {
name: this.$route.matched[idx].name
......@@ -94,10 +101,10 @@ export default defineComponent({
const parentBreadCrumbs = this.parentProjects.map((parentProject) => {
return {
to: {
name: "project-home",
name: "project-page",
params: { slug: parentProject.slug },
},
text: this.$t(`breadcrumbs.project.home`, {
text: this.$t(`breadcrumbs.project.page`, {
projectName: parentProject.displayName,
}).toString(),
} as RouteLink;
......
<template>
<div>
<b-modal
:visible="value"
@change="$emit('input', value)"
:title="title"
@hidden="hideModal"
:hide-footer="hideFooter"
:hide-footer="true"
>
<div>
{{ headerText }}
{{ body }}
</div>
<slot></slot>
<slot v-if="hideFooter" name="footer"></slot>
<template #modal-footer>
<div>
<b-button variant="secondary" style="margin-left: -24.5rem">
{{ $t("cancel") }}
</b-button>
<b-button
variant="danger"
@click="$emit('confirmModal')"
style="float: right"
>
{{ $t("delete") }}
</b-button>
</div>
</template>
<slot />
<slot name="buttons" />
</b-modal>
</div>
</template>
<script lang="ts">
......@@ -36,20 +20,16 @@ import { defineComponent } from "vue-demi";
export default defineComponent({
name: "CoscineModal",
props: {
hideFooter: {
default: false,
type: Boolean,
},
value: {
default: false,
type: Boolean,
},
title: {
default: null,
default: "",
type: String,
},
headerText: {
default: null,
body: {
default: "",
type: String,
},
},
......
<template>
<b-toast
v-model="loginStore.expiredSession"
toaster="b-toaster-bottom-right"
variant="danger"
solid
no-auto-hide
no-close-button
:title="$t('toast.session.title')"
>
<p class="text-center">{{ $t("toast.session.message") }}</p>
<div class="d-flex justify-content-center">
<b-button
class="mt-2"
size="sm"
variant="secondary"
@click="redirectToLogin"
>
{{ $t("toast.session.link") }}
</b-button>
</div>
</b-toast>
</template>
<script lang="ts">
import { defineComponent } from "@vue/composition-api";
import * as jose from "jose";
import moment from "moment";
import { useMainStore } from "@/store/index";
import { useLoginStore } from "@/modules/login/store";
export default defineComponent({
setup() {
const mainStore = useMainStore();
const loginStore = useLoginStore();
return { mainStore, loginStore };
},
computed: {
token(): string {
return this.mainStore.coscine.authorization.bearer;
},
},
data() {
return {
tokenExpiredInterval: 0,
};
},
created() {
this.initialize();
},
watch: {
token() {
this.initialize();
},
},
methods: {
getCurrentTokenExpirationDuration(): number {
const jwt = jose.decodeJwt(this.token);
const now = moment.utc(moment.now());
if (jwt.exp) {
// Use UTC to avoid time conversion errors
const tokenExpiresAt = moment(jwt.exp * 1000).utc();
const untilTokenExpiration = moment.duration(tokenExpiresAt.diff(now));
// Return as milliseconds for setInterval() method
return untilTokenExpiration.asMilliseconds();
}
return 0;
},
initialize() {
this.loginStore.expiredSession = false;
if (this.tokenExpiredInterval) {
clearInterval(this.tokenExpiredInterval);
}
if (this.token) {
this.tokenExpiredInterval = this.setInterval(
this.notifyTokenExpired,
this.getCurrentTokenExpirationDuration()
);
}
},
notifyTokenExpired() {
this.loginStore.expiredSession = true;
// Cancel interval expiration check
clearInterval(this.tokenExpiredInterval);
},
redirectToLogin() {
this.loginStore.redirectToLogin(this.$route, true);
},
setInterval(fn: () => void, delay: number) {
const maxDelay = Math.pow(2, 31) - 1;
if (delay > maxDelay) {
return setInterval(fn, maxDelay);
}
return setInterval(fn, delay);
},
},
});
</script>
<template>
<b-overlay
id="overlay-background"
no-wrap
:fixed="true"
:show="isWaitingForResponse"
:variant="'white'"
:opacity="0.9"
:z-index="2000"
:blur="''"
rounded="sm"
>
<template #overlay>
<div class="text-center">
<h5 class="mb-3">{{ textBefore }}</h5>
<b-spinner
label="Loading ..."
class="b-spinner-opts"
:style="{ color: color }"
>
</b-spinner>
<h5 class="mt-3">{{ textAfter }}</h5>
</div>
</template>
</b-overlay>
</template>
<script lang="ts">
export default {
name: "LoadingSpinner",
props: {
color: {
default: "#00549f",
type: String,
},
isWaitingForResponse: {
default: false,
type: Boolean,
},
textBefore: {
default: "",
type: String,
},
textAfter: {
default: "",
type: String,
},
},
};
</script>
<style>
.b-spinner-opts {
height: 8rem;
width: 8rem;
}
</style>
......@@ -22,7 +22,7 @@
<b-nav-form @submit.stop.prevent="triggerSearch">
<b-input-group size="sm" style="width: 25rem">
<template #prepend>
<b-button @click="triggerSearch">
<b-button :disabled="!searchTerm" @click="triggerSearch">
<b-icon icon="search" />
</b-button>
</template>
......@@ -139,14 +139,14 @@ export default defineComponent({
};
},
computed: {
user(): null | UserObject {
return this.userStore.user;
locales(): Array<string> {
return this.$root.$i18n.availableLocales;
},
loggedIn(): boolean {
return this.mainStore.loggedIn;
},
locales(): Array<string> {
return this.$root.$i18n.availableLocales;
user(): null | UserObject {
return this.userStore.user;
},
},
methods: {
......@@ -159,8 +159,11 @@ export default defineComponent({
this.loginStore.logout();
},
triggerSearch() {
// If searchTerm is not empty
if (this.searchTerm) {
// attach search query, resulting in "/search?q=<searchTerm>"
this.$router.push({ name: "search", query: { q: this.searchTerm } });
}
},
toggleSidebar() {
this.mainStore.sidebarActive = !this.mainStore.sidebarActive;
......
......@@ -36,6 +36,7 @@ import { useResourceStore } from "@/modules/resource/store";
import type {
ProjectObject,
ResourceObject,
RoleObject,
} from "@coscine/api-client/dist/types/Coscine.Api.Project";
import VueSidebarMenu from "vue-sidebar-menu";
......@@ -45,7 +46,6 @@ import type {
SidebarComponentItem,
SidebarHeaderItem,
} from "vue-sidebar-menu";
import { RawLocation } from "vue-router";
Vue.use(VueSidebarMenu);
......@@ -68,16 +68,20 @@ export default defineComponent({
};
},
computed: {
currentUserRole(): RoleObject | undefined | null {
return this.projectStore.currentUserRole;
},
menu(): Array<SidebarItem | SidebarComponentItem | SidebarHeaderItem> {
return [
{
href: "/",
title: this.$t("sidebarmenu.home").toString(),
title: this.$t("sidebar.home").toString(),
icon: "bi bi-house",
},
...this.projectMenu,
...this.projectsMenu,
...this.projectMenu,
...this.resourcesMenu,
...this.subProjectsMenu,
...this.settingsMenu,
];
},
......@@ -85,20 +89,18 @@ export default defineComponent({
return this.projectStore.currentProject;
},
projects(): ProjectObject[] | null {
return this.projectStore.allProjects;
return this.projectStore.topLevelProjects;
},
projectMenu(): Array<
SidebarItem | SidebarComponentItem | SidebarHeaderItem
> {
projectMenu(): Array<SidebarItem> {
if (this.project && this.project.slug) {
return [
{
href: {
name: "project-home",
name: "project-page",
params: { slug: this.project.slug },
},
title:
this.$t("sidebarmenu.project").toString() +
this.$tc("sidebar.project", 1).toString() +
": " +
this.project.displayName,
icon: "bi bi-folder-symlink",
......@@ -107,25 +109,23 @@ export default defineComponent({
}
return [];
},
projectsMenu(): Array<
SidebarItem | SidebarComponentItem | SidebarHeaderItem
> {
if (this.projects && this.projects.length) {
projectsMenu(): Array<SidebarItem> {
if (this.projects && this.projects.length && !this.project) {
return [
{
title: this.$t("sidebarmenu.projects").toString(),
href: {},
title: this.$tc("sidebar.project", 2).toString(),
href: "",
icon: "bi bi-folder2-open",
child: this.projects.map((project) => {
return {
title: project.displayName,
href: {
name: "project-home",
params: { slug: project.slug! },
name: "project-page",
params: { slug: project.slug },
},
icon: "bi bi-folder2-open",
};
}) as Array<SidebarItem | SidebarComponentItem | SidebarHeaderItem>,
}) as Array<SidebarItem>,
},
];
}
......@@ -134,24 +134,30 @@ export default defineComponent({
resources(): ResourceObject[] | null {
return this.projectStore.currentResources;
},
resourcesMenu(): Array<
SidebarItem | SidebarComponentItem | SidebarHeaderItem
> {
if (this.resources && this.resources.length && this.project) {
resourcesMenu(): Array<SidebarItem> {
if (
this.resources &&
this.resources.length &&
this.project &&
this.project.slug
) {
return [
{
title: this.$t("sidebarmenu.resources").toString(),
href: {},
title: this.$tc("sidebar.resource", 2).toString(),
href: "",
icon: "bi bi-archive",
child: this.resources.map((resource) => {
return {
title:
(resource.type?.displayName
? resource.type.displayName + ": "
? resource.type.displayName.toUpperCase() + ": "
: "") + resource.displayName,
href: {
name: "resource-home",
params: { slug: this.project!.slug!, guid: resource.id! },
name: "resource-page",
params: {
slug: this.project ? this.project.slug : undefined,
guid: resource.id,
},
},
icon: "bi bi-archive",
badge: resource.archived
......@@ -161,24 +167,27 @@ export default defineComponent({
}
: undefined,
};
}) as Array<SidebarItem | SidebarComponentItem | SidebarHeaderItem>,
}) as Array<SidebarItem>,
},
];
}
return [];
},
settingsMenu(): Array<
SidebarItem | SidebarComponentItem | SidebarHeaderItem
> {
if (this.project && this.project.slug) {
settingsMenu(): Array<SidebarItem> {
if (
this.project &&
this.project.slug &&
this.currentUserRole &&
this.currentUserRole.displayName === "Owner"
) {
return [
{
title: this.$t("sidebarmenu.settings").toString(),
href: {},
title: this.$t("sidebar.settings").toString(),
href: "",
icon: "bi bi-gear",
child: [
{
title: this.$t("sidebarmenu.editProject").toString(),
title: this.$t("sidebar.projectSettings").toString(),
href: {
name: "project-settings",
params: { slug: this.project.slug },
......@@ -186,7 +195,7 @@ export default defineComponent({
icon: "bi bi-pencil",
},
{
title: this.$t("sidebarmenu.manageUsers").toString(),
title: this.$t("sidebar.manageUsers").toString(),
href: {
name: "project-members",
params: { slug: this.project.slug },
......@@ -194,7 +203,7 @@ export default defineComponent({
icon: "bi bi-people",
},
{
title: this.$t("sidebarmenu.manageQuota").toString(),
title: this.$t("sidebar.manageQuota").toString(),
href: {
name: "project-quota",
params: { slug: this.project.slug },
......@@ -210,6 +219,31 @@ export default defineComponent({
sidebarActive(): boolean {
return this.mainStore.sidebarActive;
},
subProjects(): ProjectObject[] | null {
return this.projectStore.currentSubProjects;
},
subProjectsMenu(): Array<SidebarItem> {
if (this.subProjects && this.subProjects.length) {
return [
{
title: this.$tc("sidebar.subProject", 2).toString(),
href: "",
icon: "bi bi-folder2-open",
child: this.subProjects.map((project) => {
return {
title: project.displayName,
href: {
name: "project-page",
params: { slug: project.slug },
},
icon: "bi bi-folder2-open",
};
}) as Array<SidebarItem>,
},
];
}
return [];
},
},
watch: {
collapsed() {
......
<template>
<b-alert
v-if="visibility"
:show="
visibility && maintenance.type !== undefined && maintenance.type !== null
"
@dismissed="saveVisibility"
dismissible
variant="warning"
>
<i18n :path="messagePath" tag="p">
<template v-slot:link>
<a :href="maintenance.url" target="_blank">{{
$t("banner.maintenance.moreInformation")
}}</a>
</template>
</i18n>
</b-alert>
</template>
<script lang="ts">
import { defineComponent } from "vue-demi";
// import the main store
import { useMainStore } from "@/store/index";
import type { MaintenanceReturnObject } from "@coscine/api-client/dist/types/Coscine.Api.Notices";
export default defineComponent({
setup() {
const mainStore = useMainStore();
return { mainStore };
},
data() {
return {
messagePath: "",
};
},
computed: {
maintenance(): MaintenanceReturnObject {
return this.mainStore.coscine.banner.maintenance;
},
visibility(): boolean {
return (
this.mainStore.coscine.banner.maintenanceVisibility !==
this.mainStore.coscine.banner.dateString &&
this.mainStore.coscine.banner.dateString !== ""
);
},
},
watch: {
maintenance() {
this.messagePath = this.createNotificationText();
},
},
methods: {
saveVisibility() {
this.mainStore.coscine.banner.maintenanceVisibility =
this.mainStore.coscine.banner.dateString;
},
createNotificationText(): string {
if (this.maintenance && this.maintenance.type) {
switch (this.maintenance.type) {
case "Eingriff":
return "banner.maintenance.notificationDeployment";
case "Störung":
return "banner.maintenance.notificationMaintenance";
case "Teilstörung":
return "banner.maintenance.notificationPartiaMulfunction";
case "Unterbrechung":
return "banner.maintenance.notificationInteruption";
case "eingeschränkt betriebsfähig":
return "banner.maintenance.notificationLimitedOperability";
case "Wartung":
return "banner.maintenance.notificationMaintenance";
case "Teilwartung":
return "banner.maintenance.notificationPartialMaintenance";
default:
return "banner.maintenance.notificationDefaultText";
}
} else {
return "";
}
},
},
});
</script>
<style></style>
<template>
<b-alert
v-if="pilotVisibility"
:show="pilotVisibility"
@dismissed="saveVisibility"
dismissible
variant="warning"
>
<i18n path="banner.pilot.pilotBannerText" tag="p">
<template v-slot:link>
<a :href="$t('email.serviceDeskMailTo')" target="_blank">{{
$t("email.serviceDeskName")
}}</a>
</template>
</i18n>
</b-alert>
</template>
<script lang="ts">
import { defineComponent } from "vue-demi";
import { useMainStore } from "@/store/index";
export default defineComponent({
setup() {
const mainStore = useMainStore();
return { mainStore };
},
computed: {
pilotVisibility(): boolean {
return this.mainStore.coscine.banner.pilotVisibility;
},
},
methods: {
saveVisibility() {
this.mainStore.coscine.banner.pilotVisibility = false;
},
},
});
</script>
<style></style>
......@@ -28,33 +28,46 @@ export default {
},
} as VueI18n.LocaleMessageObject,
sidebarmenu: {
sidebar: {
home: "Übersicht",
project: "Projekt",
projects: "Projekte",
resources: "Ressourcen",
project: "Projekt | Projekte",
resource: "Ressource | Ressourcen",
subProject: "Unterprojekt | Unterprojekte",
settings: "Einstellungen",
archived: "Archiviert",
editProject: "Projekt bearbeiten",
manageUsers: "Mitglieder verwalten",
projectSettings: "Projekteinstellungen",
manageUsers: "Benutzerverwaltung",
manageQuota: "Quota verwalten",
} as VueI18n.LocaleMessageObject,
buttons: {
addUser: "Benutzer hinzufügen",
back: "Zurück",
cancel: "Abbrechen",
close: "Schließen",
connect: "Verbinden",
connected: "Verbunden",
copyMetadata: "Metadaten kopieren",
delete: "Löschen",
reset: "Zurücksetzen",
import: "Importieren",
invite: "Einladen",
leave: "Verlassen",
remove: "Entfernen",
resend: "Erneut senden",
revoke: "Widerrufen",
save: "Speichern",
submit: "Abschicken",
tokenCreate: "Zugriffstoken erstellen",
} as VueI18n.LocaleMessageObject,
default: {
serviceDeskEmail: "servicedesk@rwth-aachen.de",
archive: "Archivieren",
archived: "Archiviert",
loading: "Laden...",
},
toast: {
......@@ -63,6 +76,17 @@ export default {
message: "Um weiterzuarbeiten, loggen Sie sich erneut ein:",
link: "@:(nav.userLogIn)",
},
save: {
success: {
title: "Änderungen erfolgreich",
message: "Die Daten wurden erfolgreich gespeichert.",
},
failure: {
title: "Fehler beim Speichern",
message:
"Es ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut. Falls der Fehler weiterhin auftritt, wenden Sie sich bitte an @:(default.serviceDeskEmail).",
},
},
},
breadcrumbs: {
......@@ -75,14 +99,14 @@ export default {
notFound: "Nicht Gefunden",
},
project: {
home: "{projectName}",
page: "{projectName}",
create: "Projekt erstellen",
settings: "Projekt bearbeiten",
quota: "Quota Management",
members: "Benutzerverwaltung",
},
resource: {
home: "{resourceName}",
page: "{resourceName}",
create: "Ressource erstellen",
settings: "Ressource bearbeiten",
},
......@@ -90,4 +114,108 @@ export default {
profile: "Nutzerprofil",
},
},
ResourceTypes: {
rds: {
displayName: "RWTH-FDS-Web",
fullName: "Forschungsdatenspeicher (FDS)",
description:
"Forschungsdatenspeicher (FDS) ist objektbasierter Speicher für Forschungsdaten. Sie können FDS-Resourcen mit Speicherplatz für Ihre Forschungsdaten erstellen solange das Projekt ausreichend Speicherquota hat. Projektbesitzer können zusätzliche Speicherquota beantragen.",
},
rdsude: {
displayName: "UDE-FDS-Web",
fullName: "Forschungsdatenspeicher (FDS)",
description:
"Forschungsdatenspeicher (FDS) Universität Duisburg-Essen ist objektbasierter Speicher für Forschungsdaten. Sie können FDS-Resourcen mit Speicherplatz für Ihre Forschungsdaten erstellen solange das Projekt ausreichend Speicherquota hat. Projektbesitzer können zusätzliche Speicherquota beantragen.",
},
rdstudo: {
displayName: "TUDO-FDS-Web",
fullName: "Forschungsdatenspeicher (FDS)",
description:
"Forschungsdatenspeicher (FDS) Technische Universität Dortmund ist objektbasierter Speicher für Forschungsdaten. Sie können FDS-Resourcen mit Speicherplatz für Ihre Forschungsdaten erstellen solange das Projekt ausreichend Speicherquota hat. Projektbesitzer können zusätzliche Speicherquota beantragen.",
},
rdsnrw: {
displayName: "NRW-FDS-Web",
fullName: "Forschungsdatenspeicher (FDS)",
description:
"Forschungsdatenspeicher (FDS) Nordrhein-Westfalen ist objektbasierter Speicher für Forschungsdaten. Sie können FDS-Resourcen mit Speicherplatz für Ihre Forschungsdaten erstellen solange das Projekt ausreichend Speicherquota hat. Projektbesitzer können zusätzliche Speicherquota beantragen.",
},
s3: {
displayName: "S3 Bucket",
fullName: "S3 Bucket (S3)",
description:
"S3 Buckets (S3) sind objektbasierte Speichereinheiten für Forschungsdaten. Sie basieren auf der gleichen Technik wie der Forschungsdatenspeicher (FDS), die Verwaltung der Metadaten liegt jedoch beim Nutzer. Daher ist ein gesondertes Antragsverfahren und ein Datenmanagementplan (DMP) notwendig, um sicherzustellen, dass die Daten die in S3 Buckets gespeichert werden mit Metadaten beschrieben werden um langfristig auffindbar und nachnutzbar zu sein.",
},
rdss3: {
displayName: "RWTH-FDS-S3",
fullName: "FDS-S3-Ressource (S3)",
description:
"FDS-S3 sind objektbasierte Speichereinheiten für Forschungsdaten. Sie basieren auf der gleichen Technik wie der Forschungsdatenspeicher (FDS), die Verwaltung der Metadaten liegt jedoch beim Nutzer. Daher ist ein Antragsverfahren notwendig, um sicherzustellen, dass die Daten die in FDS-S3 gespeichert werden mit Metadaten beschrieben werden um langfristig auffindbar und nachnutzbar zu sein.",
},
rdss3ude: {
displayName: "UDE-FDS-S3",
fullName: "FDS-S3-Ressource (S3)",
description:
"FDS-S3 Universität Duisburg-Essen sind objektbasierte Speichereinheiten für Forschungsdaten. Sie basieren auf der gleichen Technik wie der Forschungsdatenspeicher (FDS), die Verwaltung der Metadaten liegt jedoch beim Nutzer. Daher ist ein Antragsverfahren notwendig, um sicherzustellen, dass die Daten die in FDS-S3 gespeichert werden mit Metadaten beschrieben werden um langfristig auffindbar und nachnutzbar zu sein.",
},
rdss3tudo: {
displayName: "TUDO-FDS-S3",
fullName: "FDS-S3-Ressource (S3)",
description:
"FDS-S3 Technische Universität Dortmund sind objektbasierte Speichereinheiten für Forschungsdaten. Sie basieren auf der gleichen Technik wie der Forschungsdatenspeicher (FDS), die Verwaltung der Metadaten liegt jedoch beim Nutzer. Daher ist ein Antragsverfahren notwendig, um sicherzustellen, dass die Daten die in FDS-S3 gespeichert werden mit Metadaten beschrieben werden um langfristig auffindbar und nachnutzbar zu sein.",
},
rdss3nrw: {
displayName: "NRW-FDS-S3",
fullName: "FDS-S3-Ressource (S3)",
description:
"FDS-S3 Nordrhein-Westfalen sind objektbasierte Speichereinheiten für Forschungsdaten. Sie basieren auf der gleichen Technik wie der Forschungsdatenspeicher (FDS), die Verwaltung der Metadaten liegt jedoch beim Nutzer. Daher ist ein Antragsverfahren notwendig, um sicherzustellen, dass die Daten die in FDS-S3 gespeichert werden mit Metadaten beschrieben werden um langfristig auffindbar und nachnutzbar zu sein.",
},
gitlab: {
displayName: "Gitlab",
fullName: "Gitlab (Git)",
description:
"Gitlab (Git) ist eine Webanwendung zur Versionsverwaltung für Softwareprojekte auf Git-Basis. Sie können Git-Repositorien in Ihren CoScInE Projekten hinterlegen und mit Metadaten beschreiben. Im Arbeitsalltag können Sie Git wie gewohnt nutzen und haben in CoScInE die Übersicht über verschiedene Repositorien und die Möglichkeit zur Metadatenverwaltung.",
},
linked: {
displayName: "Linked Data",
fullName: "Linked Data (Linked)",
description:
"Linked Data Ressourcen erlauben das Metadatenmanagemnent für Daten die in externen Speichersystemen liegen auf die nicht direkt per Coscine zugegriffen werden kann oder soll. So können z.B. Daten auf lokalen Datenspeichern im Institut oder externen Datenspeichern die nicht mit Coscine kompatibel sind mit Metadaten beschreiben werden. Die Handhabung der Metadaten erfolgt weitgehend analog zu anderen Ressourcentypen, statt dem Upload- und Download von Daten werden Platzhalter angelegt die mit den Metadaten beschrieben werden. Durch ein zusätzliches Feld kann eine Referenz auf den Ort der Datei angegeben werden um eine eindeutige Zuordnung auf Dateilevel zu erlauben, z. B. Institutsfileserver/Projekt X/Messreihe B/11-12-2020_data.csv.",
},
},
banner: {
pilot: {
pilotBannerText: `Coscine befindet sich derzeit in der ersten Pilotphase. Sie können sich also gerne
einloggen und das System erkunden, aber aufgrund aktiver Entwicklungen kann es zu
technischen Schwierigkeiten kommen. Bitte kontaktieren Sie uns,
wenn Sie an dem Pilotprogramm teilnehmen möchten. Feedback und
Verbesserungsvorschläge können Sie gerne an [{link}] senden.`,
},
maintenance: {
notificationDefaultText:
"Derzeit kann es unter Umständen zu Einschränkungen bei der Nutzung von Coscine kommen. Details finden Sie unter [{link}].",
notificationDeployment:
"Derzeit kann es unter Umständen zu Einschränkungen bei der Nutzung von Coscine kommen.",
notificationMalfunction:
"Durch eine Störung ist Coscine derzeit nicht verfügbar. Details finden Sie unter [{link}].",
notificationPartiaMulfunction:
"Durch eine Teilstörung ist Coscine derzeit nicht verfügbar. Details finden Sie unter [{link}].",
notificationInteruption:
"Durch die Unterbrechung eines Dienstes ist Coscine derzeit nicht verfügbar. Details finden Sie unter [{link}].",
notificationLimitedOperability:
"Coscine ist derzeit nur eingeschränkt verfügbar. Details finden Sie unter [{link}].",
notificationMaintenance:
"Coscine wird derzeit gewartet. Es können Einschränkungen bei der Nutzung auftreten. Details finden Sie unter [{link}].",
notificationPartialMaintenance:
"Coscine wird derzeit gewartet. Es können Einschränkungen bei der Nutzung auftreten. Details finden Sie unter [{link}].",
moreInformation: "weitere Informationen",
},
},
email: {
serviceDeskName: "Servicedesk",
serviceDeskMailTo:
"mailto:servicedesk@itc.rwth-aachen.de?subject=CoScInE%20Pilot%20Program",
},
} as VueI18n.LocaleMessageObject;
......@@ -28,31 +28,43 @@ export default {
},
} as VueI18n.LocaleMessageObject,
sidebarmenu: {
sidebar: {
home: "Home",
project: "Project",
projects: "Projects",
resources: "Resources",
project: "Project | Projects",
resource: "Resource | Resources",
subProject: "Sub-Project | Sub-Projects",
settings: "Settings",
editProject: "Edit Project",
projectSettings: "Project Settings",
manageUsers: "Manage Users",
manageQuota: "Manage Quota",
} as VueI18n.LocaleMessageObject,
buttons: {
addUser: "Add User",
back: "Back",
cancel: "Cancel",
close: "Close",
connect: "Connect",
connected: "Connected",
copyMetadata: "Copy Metadata",
delete: "Delete",
reset: "Reset",
import: "Import",
invite: "Invite",
leave: "Leave",
remove: "Remove",
resend: "Resend",
revoke: "Revoke",
save: "Save",
submit: "Submit",
tokenCreate: "Create Access Token",
} as VueI18n.LocaleMessageObject,
default: {
archive: "Archive",
archived: "Archived",
loading: "Loading...",
},
toast: {
......@@ -61,6 +73,17 @@ export default {
message: "To continue working, log in again:",
link: "@:(nav.userLogIn)",
},
onSave: {
success: {
title: "Saved successfully",
message: "The data has been saved successfully.",
},
failure: {
title: "Error on saving",
message:
"An error occured. Please try again. If the error persists, please contact @:(default.serviceDeskEmail).",
},
},
},
breadcrumbs: {
......@@ -73,19 +96,122 @@ export default {
notFound: "Not Found",
},
project: {
home: "{projectName}",
page: "{projectName}",
create: "Create Project",
settings: "Edit Project",
settings: "Project Settings",
quota: "Quota Management",
members: "User Management",
},
resource: {
home: "{resourceName}",
page: "{resourceName}",
create: "Create Resource",
settings: "Edit Resource",
settings: "Resource Settings",
},
user: {
profile: "User Profile",
},
},
ResourceTypes: {
rds: {
displayName: "RWTH-RDS-Web",
fullName: "Research Data Storage (RDS)",
description:
"Research Data Storage (RDS) is object-based storage for research data. You can create RDS resources with storage space for your research data as long as the project has sufficient storage quota. Project owners can request additional storage quota.",
},
rdsude: {
displayName: "UDE-RDS-Web",
fullName: "Research Data Storage (RDS)",
description:
"Research Data Storage (RDS) University of Duisburg-Essen is object-based storage for research data. You can create RDS resources with storage space for your research data as long as the project has sufficient storage quota. Project owners can request additional storage quota.",
},
rdstudo: {
displayName: "TUDO-RDS-Web",
fullName: "Research Data Storage (RDS)",
description:
"Research Data Storage (RDS) TU Dortmund University is object-based storage for research data. You can create RDS resources with storage space for your research data as long as the project has sufficient storage quota. Project owners can request additional storage quota.",
},
rdsnrw: {
displayName: "NRW-RDS-Web",
fullName: "Research Data Storage (RDS)",
description:
"Research Data Storage (RDS) North Rhine-Westphalia is object-based storage for research data. You can create RDS resources with storage space for your research data as long as the project has sufficient storage quota. Project owners can request additional storage quota.",
},
s3: {
displayName: "S3 Bucket",
fullName: "S3 Bucket (S3)",
description:
"S3 Buckets (S3) are object-based storage units for research data They are based on the same technology as the research data storage (RDS), but the administration of the metadata lies with the user. Therefore, a separate application procedure and a data management plan (DMP) is necessary to ensure that the data stored in S3 Buckets is described with metadata in order to be retrievable and reusable in the long term.",
},
rdss3: {
displayName: "RWTH-RDS-S3",
fullName: "RDS-S3-Resource (S3)",
description:
"RDS-S3 are object-based storage units for research data. They are based on the same technology as the research data storage (RDS), but the administration of the metadata lies with the user. Therefore, an application procedure is necessary to ensure that the data stored in S3 Buckets is described with metadata in order to be retrievable and reusable in the long term.",
},
rdss3ude: {
displayName: "UDE-RDS-S3",
fullName: "RDS-S3-Resource (S3)",
description:
"RDS-S3 University of Duisburg-Essen are object-based storage units for research data. They are based on the same technology as the research data storage (RDS), but the administration of the metadata lies with the user. Therefore, an application procedure is necessary to ensure that the data stored in S3 Buckets is described with metadata in order to be retrievable and reusable in the long term.",
},
rdss3tudo: {
displayName: "TUDO-RDS-S3",
fullName: "RDS-S3-Resource (S3)",
description:
"RDS-S3 TU Dortmund University are object-based storage units for research data. They are based on the same technology as the research data storage (RDS), but the administration of the metadata lies with the user. Therefore, an application procedure is necessary to ensure that the data stored in S3 Buckets is described with metadata in order to be retrievable and reusable in the long term.",
},
rdss3nrw: {
displayName: "NRW-RDS-S3",
fullName: "RDS-S3-Resource (S3)",
description:
"RDS-S3 North Rhine-Westphalia are object-based storage units for research data. They are based on the same technology as the research data storage (RDS), but the administration of the metadata lies with the user. Therefore, an application procedure is necessary to ensure that the data stored in S3 Buckets is described with metadata in order to be retrievable and reusable in the long term.",
},
gitlab: {
displayName: "Gitlab",
fullName: "Gitlab (Git)",
description:
"Gitlab (Git) is a web application for version management of software projects based on Git. You can store Git repositories in your CoScInE projects and describe them with metadata. In your daily work you can use Git as usual and have an overview of different repositories and the possibility to manage metadata in CoScInE.",
},
linked: {
displayName: "Linked Data",
fullName: "Linked Data (Linked)",
description:
"Linked Data Resources allow metadata management for data stored in external storage systems that cannot or should not be directly accessed via Coscine. For example, data on local data storage systems in the institute or external data storage systems that are not compatible with Coscine can be described with metadata. The handling of metadata is largely analogous to other resource types. Instead of uploading and downloading data, placeholders are created which are described with the metadata. An additional field can be used to specify a reference to the location of the file in order to allow a unique assignment at file level, e.g. Institute file server/Project X/Measurement B/11-12-2020_data.csv.",
},
},
banner: {
pilot: {
pilotBannerText: `Coscine is currently in the first pilot phase. So you are welcome to
log in and explore the system, but you may experience technical difficulties
due to active developments. Please contact us if you want to be part of the
pilot program. If you have feedback you are welcome to send it to [{link}].`,
},
maintenance: {
notificationDefaultText:
"Currently, you may experience restrictions when using Coscine. Details can be found at [{link}].",
notificationDeployment:
"Currently, you may experience restrictions when using Coscine.",
notificationMalfunction:
"Due to a malfunction Coscine is currently unavailable. Details can be found at [{link}].",
notificationPartiaMulfunction:
"Due to a partial malfunction Coscine is currently unavailable. Details can be found at [{link}].",
notificationInteruption:
"Due to a interuption of a service Coscine is currently unavailable. Details can be found at [{link}].",
notificationLimitedOperability:
"Coscine is currently offering limited operability. Details can be found at [{link}].",
notificationMaintenance:
"Coscine is currently undergoing maintenance. You may experience restrictions in its use. Details can be found at [{link}].",
notificationPartialMaintenance:
"Coscine is currently undergoing maintenance. You may experience restrictions in its use. Details can be found at [{link}].",
moreInformation: "more information",
},
},
email: {
serviceDeskName: "Servicedesk",
serviceDeskMailTo:
"mailto:servicedesk@itc.rwth-aachen.de?subject=CoScInE%20Pilot%20Program",
},
} as VueI18n.LocaleMessageObject;
import { defineStore } from "pinia";
import { LoginState } from "./types";
import VueRouter, { RawLocation, Route } from "vue-router";
import { RawLocation, Route } from "vue-router";
// import the main store
import { useMainStore } from "@/store/index";
......@@ -17,7 +17,9 @@ export const useLoginStore = defineStore({
STATES
--------------------------------------------------------------------------------------
*/
state: (): LoginState => ({}),
state: (): LoginState => ({
expiredSession: false,
}),
/*
--------------------------------------------------------------------------------------
......
......@@ -4,4 +4,5 @@ export interface LoginState {
STATE TYPE DEFINITION
--------------------------------------------------------------------------------------
*/
expiredSession: boolean;
}
......@@ -10,6 +10,7 @@ import { ProjectI18nMessages } from "./i18n";
// import the store for current module
import { useProjectStore } from "./store";
import { useResourceStore } from "@/modules/resource/store";
// import the main store
import { useMainStore } from "@/store/index";
......@@ -20,8 +21,9 @@ export default defineComponent({
setup() {
const mainStore = useMainStore();
const projectStore = useProjectStore();
const resourceStore = useResourceStore();
return { mainStore, projectStore };
return { mainStore, projectStore, resourceStore };
},
i18n: { messages: ProjectI18nMessages },
......@@ -39,7 +41,11 @@ export default defineComponent({
this.projectStore.currentSlug !== null &&
this.projectStore.currentProject !== null &&
this.projectStore.currentResources !== null &&
this.projectStore.currentSubProjects !== null
this.projectStore.currentSubProjects !== null &&
this.projectStore.currentQuotas !== null &&
this.resourceStore.resourceTypes !== null &&
this.projectStore.currentProjectRoles !== null &&
this.projectStore.roles !== null
);
},
},
......@@ -52,6 +58,10 @@ export default defineComponent({
async apiFetch(route: Route) {
// Project may be unset (e.g. when entering from a direct link)
await this.projectStore.handleUnsetProject(this.project, route);
// Load All Projects if not present
if (this.projectStore.allProjects === null) {
this.projectStore.retrieveAllProjects();
}
// Load Resources for the project if not present
if (this.projectStore.currentResources === null) {
this.projectStore.retrieveResources(this.project);
......@@ -64,6 +74,20 @@ export default defineComponent({
if (this.projectStore.currentProjectRoles === null) {
this.projectStore.retrieveProjectRoles(this.project);
}
// Load Quotas for the project if not present
if (this.projectStore.currentQuotas === null) {
this.projectStore.retrieveQuotas(this.project);
}
if (this.resourceStore.resourceTypes === null) {
this.resourceStore.retrieveResourceTypes();
}
if (this.projectStore.roles === null) {
this.projectStore.retrieveRoles();
}
// Load Invitations for the project if not present
if (this.projectStore.currentInvitations === null) {
this.projectStore.retrieveInvitations(this.project);
}
},
},
......
......@@ -30,18 +30,37 @@ export default defineComponent({
moduleIsReady(): boolean {
return (
this.projectStore !== null &&
this.projectStore.topLevelProjects !== null
this.projectStore.topLevelProjects !== null &&
this.projectStore.roles !== null
);
},
},
methods: {
async initialize() {
await this.apiFetch();
},
async apiFetch() {
// Clear the current slug
this.projectStore.currentSlug = null;
// Load All Projects if not present
if (this.projectStore.allProjects === null) {
this.projectStore.retrieveAllProjects();
}
// Load Top Level Projects if not present
if (this.projectStore.topLevelProjects === null) {
this.projectStore.retrieveTopLevelProjects();
await this.projectStore.retrieveTopLevelProjects();
}
if (this.projectStore.roles === null) {
this.projectStore.retrieveRoles();
}
},
},
async beforeRouteUpdate(to, from, next) {
await this.apiFetch();
next();
},
});
</script>
import { OrganizationObject } from "@coscine/api-client/dist/types/Coscine.Api.Project";
export const defaultOrganizations = [
{
displayName: "FH Aachen",
url: "https://ror.org/04tqgg260",
} as OrganizationObject,
{
displayName: "Karlsruhe Institute of Technology",
url: "https://ror.org/04t3en479",
} as OrganizationObject,
{
displayName: "RWTH Aachen University",
url: "https://ror.org/04xfq0f34",
} as OrganizationObject,
{
displayName: "Technical University of Munich",
url: "https://ror.org/02kkvpp62",
} as OrganizationObject,
{
displayName: "TU Darmstadt",
url: "https://ror.org/05n911h24",
} as OrganizationObject,
{
displayName: "TU Dortmund University",
url: "https://ror.org/01k97gp34",
} as OrganizationObject,
{
displayName: "Universitätsklinikum Aachen",
url: "https://ror.org/02gm5zw39",
} as OrganizationObject,
{
displayName: "University of Cologne",
url: "https://ror.org/00rcxh774",
} as OrganizationObject,
{
displayName: "University of Duisburg-Essen",
url: "https://ror.org/04mz5ra38",
} as OrganizationObject,
{
displayName: "University of Münster",
url: "https://ror.org/00pd74e08",
} as OrganizationObject,
] as OrganizationObject[];