diff --git a/js/costcalc_money.jsx b/js/costcalc_money.jsx
index 040aac6..1449762 100644
--- a/js/costcalc_money.jsx
+++ b/js/costcalc_money.jsx
@@ -1,198 +1,198 @@
'use strict';
// Money is the http://openexchangerates.github.io/money.js/#playground Lib
const Money = fx.noConflict()
// Become true if money conv is configured and connected correctly
let MoneyEnable = false
class CurrencySelect extends React.Component {
constructor (props) {
super(props)
this.handleCurChange = this.handleCurChange.bind(this)
const selectable = MainData.Conv.slice(0)
selectable.unshift(MainData.Currency)
this.state = {
Enable: false,
SelectCur: 0,
Cur: selectable[0],
Selectable: selectable,
prevselec: -1
}
this.moneyset(0)
}
moneyset (select) {
Money.settings =
{
from: MainData.Currency,
to: this.state.Selectable[select]
}
}
handleCurChange (select) {
if (select === '0') {
this.setState({ Enable: false })
} else {
this.setState({ Enable: true })
}
this.setState({ SelectCur: select })
this.setState({ Cur: this.state.Selectable[select] })
this.moneyset(select)
}
componentDidUpdate () {
if (this.state.prevselec !== this.state.SelectCur) {
this.props.money({ Enable: this.state.Enable, Cur: this.state.Cur })
this.state.prevselec = this.state.SelectCur
}
}
render () {
let r = 0
let rate = null
// only display the module if conversion is enable and running ok
if (MoneyEnable) {
if (this.state.Enable) {
r = Money.convert(1).toFixed(2)
rate = '1' + MainData.Currency + '=' + r + this.state.Cur
}
return (
)
} else {
return (null)
}
}
}
class PluginsCurrencyChange extends React.Component {
constructor (props) {
super(props)
this.handleCurChange = this.handleCurChange.bind(this)
this.handleCostChange = this.handleCostChange.bind(this)
const selectable = MainData.Conv.slice(0)
selectable.unshift(MainData.Currency)
this.state = {
Enable: false,
SelectCur: 0,
Cur: selectable[0],
Selectable: selectable,
prevvalue: -1,
CostError: false,
value: 0
}
}
handleCurChange (select) {
if (select === '0') {
this.setState({ Enable: false })
} else {
this.setState({ Enable: true })
}
this.setState({ SelectCur: select })
this.setState({ Cur: this.state.Selectable[select] })
this.setState({ prevvalue: -1 })
}
handleCostChange (value) {
value = value.replace(/ /g, '')
if (isNaN(value) || value === '' || typeof value === 'number') {
this.setState({ CostError: true })
value = 0
} else {
this.setState({ CostError: false })
}
this.setState({ value })
}
makecost () {
let value = this.state.value
// Convert money from another currency to the main if needed
if (this.state.Enable) {
value = Money(value).from(this.state.Cur).to(MainData.Currency)
}
// Send the value to parent plugin
this.props.onCostChange(value)
}
componentDidUpdate () {
if (this.state.prevvalue !== this.state.value) {
this.makecost()
this.state.prevvalue = this.state.value
}
}
selector () {
if (MoneyEnable) {
return (
)
} else {
return (MainData.Currency)
}
}
classtxt (error) {
if (error) {
return 'is-invalid'
} else {
return 'is-valid'
}
}
render () {
let r = 0
let rate = ''
if (this.state.Enable) {
r = Money(1.00).from(this.state.Cur).to(MainData.Currency).toFixed(2)
rate = '1' + this.state.Cur + '=' + r + MainData.Currency
}
return (
)
}
}
// This function convert the input (ie numnber or string) to the converted currency
function ConvCurrency (main_cur) {
- return tomoney(Money.convert(tonumeric(main_cur)), Money.settings.to)
+ return toMoney(Money.convert(toNumeric(main_cur)), Money.settings.to)
}
// Init function for downloading the rate from Open Exchange Rates
/**
* @return {boolean}
*/
function MoneyGetRates () {
// Load exchange rates data via AJAX:
if (MainData.OEXRApi !== '') {
const com = $.ajax({
// NB: using Open Exchange Rates here, but you can use any source!
url: 'https://openexchangerates.org/api/latest.json?app_id=' + MainData.OEXRApi,
dataType: 'json',
async: false,
success: function (data) {
Money.rates = data.rates
Money.base = data.base
}
})
.done(function () {
console.log('Money data loaded')
MoneyEnable = true
})
.fail(function () {
console.log('Error loading data money')
MoneyEnable = false
})
}
return MoneyEnable
}
diff --git a/js/data.js b/js/data.js
index 37e6f05..4e6adcb 100644
--- a/js/data.js
+++ b/js/data.js
@@ -1,629 +1,630 @@
// Providers
// ----------------------------------------------------
// ----------------------------------------------------
// Storage
const NasEpfl = {
Style: 'AmountRatesCost',
Provider: 'EPFL-VPO-DSI',
Name: 'NAS2023',
Url: [
{
Name: 'DSI-Website',
Url: 'https://support.epfl.ch/help/epfl?id=epfl_service_status&service=49a363acdb34c700ef64731b8c96191f'
}
],
ExtraInfo: '',
ByYear: true,
Adaptive: false,
AmountName: 'Amount',
AmountUnit: 'TB',
AmountMin: 0,
AmountMax: 1,
AmountStep: 1,
AmountFree: 1,
AmountFreeCumulative: false,
RateName: 'Performance',
Rates: {
Standard: 80
},
RateUnit: 'CHF / TB'
}
const RcpEpfl = {
Style: 'AmountRatesCost',
Provider: 'EPFL-VPA-RCP',
Name: 'Collaborative Storage – NAS-RCP',
Url: [
{
Name: 'Service description',
Url: 'https://www.epfl.ch/research/facilities/rcp/collaborative-storage-nas-rcp-service-description/'
}
],
ExtraInfo: '',
ByYear: true,
Adaptive: false,
AmountName: 'Amount',
AmountUnit: 'TB',
AmountMin: 0,
AmountMax: 25,
AmountStep: 1,
AmountFree: 0,
AmountFreeCumulative: false,
RateName: 'Performance',
Rates: {
Standard: 40
},
RateUnit: 'CHF / TB'
}
const SwitchEpfl = {
Style: 'CategoryCost',
Provider: 'Switch',
Name: 'Online Storage',
ByYear: true,
Url: [
{
Name: 'Switch Website',
Url: 'https://drive.switch.ch/'
}
],
CatName: 'Options',
Cat: {
'Cloud Based max 50GB': 0
},
CatUnit: 'CHF'
}
const MsPersonalEpfl = {
Style: 'CategoryCost',
Provider: 'Microsoft OneDrive',
Name: 'Microsoft M365 OneDrive',
ByYear: true,
Url: [
{
Name: 'Service description',
Url: 'https://support.epfl.ch/epfl?id=epfl_kb_article_view&sysparm_article=KB0017390&sys_kb_id=44ce400f97b729142f9976971153af0c#mcetoc_1h4lngro134'
}
],
CatName: 'Options',
Cat: {
'Individual storage 1TB': 0
},
CatUnit: 'CHF'
}
const MsSharedEpfl = {
Style: 'AmountRatesCost',
Provider: 'Microsoft SharePoint',
Name: 'Microsoft M365 SharePoint',
Url: [
{
Name: 'Service description',
Url: 'https://support.epfl.ch/epfl?id=epfl_kb_article_view&sysparm_article=KB0017390&sys_kb_id=44ce400f97b729142f9976971153af0c#mcetoc_1h4lngro137'
}
],
ByYear: true,
Adaptive: false,
AmountName: 'Amount',
AmountUnit: 'TB',
AmountMin: 0,
AmountMax: 25,
AmountStep: 1,
AmountFree: 1,
RateName: 'Standard',
Rates: {
Standard: 0
},
RateUnit: 'CHF',
AmountFreeCumulative: false
}
const GoogleDriveEdu = {
Style: 'CategoryCost',
Provider: 'Google Workspace',
Name: 'Online Storage',
ByYear: true,
Adaptive: false,
ExtraInfo: 'Google Storage is not recommended as the data are stored outside of Switzerland',
ExtraInfoUrl: 'https://support.epfl.ch/epfl?id=epfl_service_status&service=b1c22728db34c700ef64731b8c9619ad',
Url: [
{
Name: 'Google Education Page',
Url: 'https://edu.google.com/intl/en_ALL/'
}
],
AmountName: 'Amount',
AmountUnit: 'GB',
AmountMin: 0,
AmountMax: 20,
AmountStep: 1,
AmountFree: 0,
CatName: 'Options',
Cat: {
'Individual 20GB': 0,
'Group 50GB': 0
},
CatUnit: 'CHF'
}
const DropboxPerso = {
Style: 'CategoryCost',
Provider: 'Dropbox Personal',
Name: 'Online Storage',
ByYear: true,
ExtraInfo: 'Dropbox must not be used for confidential data as the data are stored outside of Switzerland',
ExtraInfoUrl: 'https://support.epfl.ch/kb_view_customer.do?sysparm_article=KB0012882',
Url: [
{ Name: 'Dropbox', Url: 'https://www.dropbox.com/plans?trigger=nr' }
],
CatName: 'Plan',
Cat: {
'Personal Free 2Go': 0,
- 'Personal Plus 2TB': 120
+ 'Personal Plus 2TB': 107,
+ 'Essentials (3TB)': 193,
},
- CatUnit: 'USD'
+ CatUnit: 'CHF'
}
const DropboxTeam = {
Style: 'AmountRatesCost',
Provider: 'Dropbox for Team',
Name: 'Online Storage',
ByYear: true,
ExtraInfo: 'Dropbox must not be used for confidential data as the data are stored outside of Switzerland',
ExtraInfoUrl: 'https://support.epfl.ch/kb_view_customer.do?sysparm_article=KB0012882',
Url: [
{
Name: 'Dropbox',
Url: 'https://www.dropbox.com/plans?trigger=nr'
}
],
Adaptive: false,
AmountName: 'Number of Users',
AmountUnit: 'Users',
AmountMin: 1,
AmountMax: 500,
AmountStep: 1,
AmountFree: 0,
AmountFreeCumulative: false,
RateName: 'Plan',
Rates: {
- Standard: 136,
- Advanced: 204
+ 'Business (9TB)': 172,
+ 'Business Plus (15TB)': 214
},
RateUnit: 'CHF / User'
}
// ELN
const SLIMSEpfl = {
Style: 'CategoryAmountRatesCost',
Provider: 'EPFL-SV-IT',
Name: 'SLIMS',
ByYear: true,
Url: [
{ Name: 'SLIMS on SV-IT Website', Url: 'https://www.epfl.ch/schools/sv/it/374-2/applications/eln-lims/' },
{ Name: 'Genohm (SLIMS Company)', Url: 'https://www.genohm.com/' }
],
CatName: 'PI Status',
Cat: {
'Full Professor': 3000,
'Associate Professor': 2000,
'Tenure Track Assistant Professor or Core Facility': 1000
},
CatUnit: 'CHF',
Adaptive: false,
AmountName: 'Storage',
AmountUnit: 'TB',
AmountMin: 1,
AmountMax: 100,
AmountStep: 1,
AmountFree: 0,
AmountFreeCumulative: false,
RateName: 'ELN Storage',
Rates: {
'Stored on EPFL Server': 45
},
RateUnit: 'CHF / TB'
}
const ELNEpfl = {
Style: 'CategoryCost',
Provider: 'ELN-EPFL',
Name: 'ELN',
ByYear: true,
Url: [
{ Name: 'ELN Website', Url: 'https://eln.epfl.ch/' }
],
CatName: 'Options',
Cat: {
'Free for EPFL community': 0
},
CatUnit: 'CHF'
}
const Rspace = {
Style: 'CategoryCost',
Provider: 'Rspace community',
Name: 'Rspace',
ByYear: true,
Url: [
{ Name: 'Rspace Website', Url: 'https://www.researchspace.com/' }
],
CatName: 'Options',
Cat: {
'Cloud Based unlimited storage and user': 0
},
CatUnit: 'CHF'
}
const Benchling = {
Style: 'CategoryCost',
Provider: 'Benchling',
Name: 'ELN',
ByYear: true,
ExtraInfo: 'The first 10GB are free',
ExtraInfoUrl: '',
Url: [
{ Name: 'Benchling website', Url: 'https://benchling.com/academic' }
],
CatName: 'Options',
Cat: {
'Cloud Based 10GB': 0
},
CatUnit: 'CHF'
}
// Database
const MysqlEpfl = {
Style: 'CategoryCost',
Provider: 'EPFL-VPO-DSI',
Name: 'MySql',
ByYear: true,
Adaptive: false,
Url: [
{ Name: 'EPFL DSI ', Url: 'https://support.epfl.ch/epfl?id=epfl_service_status&service=eb026fa0db34c700ef64731b8c96198e' }
],
CatName: 'Options',
Cat: {
'MySQL max 2GB': 0
},
CatUnit: 'CHF'
}
// Repository
const Zenodo = {
Style: 'CategoryCost',
Provider: 'Zenodo-CERN',
Name: 'Zenodo',
ByYear: false,
Adaptive: false,
Url: [
{ Name: 'Zenodo Website', Url: 'https://www.zenodo.org/' },
{ Name: 'About Zenodo', Url: 'http://about.zenodo.org/' }
],
CatName: 'Options',
Cat: {
'Max 50GB per Dataset': 0
},
CatUnit: 'CHF'
}
const C4science = {
Style: 'CategoryCost',
Provider: 'EPFL-SCITAS',
Name: 'C4Science',
Url: [
{ Name: 'C4Science Website', Url: 'https://www.c4science.ch/' }
],
ByYear: true,
Adaptive: false,
ExtraInfo: 'C4Science is a code repository and collaboration platform created by SCITAS at EPFL, accessible to all swissuniversities members.',
CatName: 'Options',
Cat: {
'Free for text file': 0
},
CatUnit: 'CHF'
}
const GitlabEPFL = {
Style: 'CategoryCost',
Provider: 'EPFL-VPO-DSI',
Name: 'Gitlab EPFL',
Url: [
{ Name: 'Gitlab EPFL', Url: 'https://gitlab.epfl.ch/' }
],
ByYear: true,
Adaptive: false,
ExtraInfo: 'A Gitlab server is operated by DSI staff at EPFL',
CatName: 'Options',
Cat: {
'Free for text file': 0
},
CatUnit: 'CHF'
}
const Github = {
Style: 'AmountRatesCost',
Provider: 'GitHub',
Name: 'GitHub',
Url: [
{ Name: 'Github Website Pricing', Url: 'https://github.com/pricing' }
],
AmountName: 'Number of user',
AmountUnit: 'User(s)',
Adaptive: true,
ByYear: true,
AmountMin: [1, 5, 10],
AmountMax: [100, 100, 100],
AmountStep: [1, 1, 1],
AmountFree: [0, 0, 0],
AmountFreeCumulative: false,
RateName: 'Plan',
Rates: {
'Free': 0,
- 'Team': 48,
- 'Enterprise': 252
+ 'Team': 43,
+ 'Enterprise': 225
},
- RateUnit: 'USD / Users'
+ RateUnit: 'CHF / Users'
}
const Bitbucket = {
Style: 'AmountRatesCost',
Provider: 'Bitbucket',
Name: 'BitBucket',
Url: [
{ Name: 'Bitbucket Website Pricing', Url: 'https://bitbucket.org/product/pricing' }
],
AmountName: 'Number of users',
AmountUnit: 'User(s)',
Adaptive: true,
ByYear: true,
AmountMin: [1, 5, 5],
AmountMax: [5, 100, 100],
AmountStep: [1, 1, 1],
AmountFree: [0, 0, 0],
AmountFreeCumulative: false,
RateName: 'Plan',
Rates: {
'Free (up to 5 users)': 0,
- 'Standard for growing teams (min 5 users)': 36,
- 'Premium for large teams (min 5 users)': 72
+ 'Standard for growing teams (min 5 users)': 32,
+ 'Premium for large teams (min 5 users)': 64
},
- RateUnit: 'USD / Users'
+ RateUnit: 'CHF / Users'
}
const Gitlab = {
Style: 'AmountRatesCost',
Provider: 'Gitlab',
Name: 'Gitlab',
Url: [
{ Name: 'Gitlab Website Pricing', Url: 'https://about.gitlab.com/pricing/' }
],
AmountName: 'Number of users',
AmountUnit: 'User(s)',
AmountMin: 1,
AmountMax: 100,
AmountStep: 1,
AmountFree: 0,
Adaptive: false,
AmountFreeCumulative: false,
ByYear: true,
RateName: 'Plan',
Rates: {
'Free (1 user, 5GB)': 0,
- 'Premium (team, 50 GB)': 348,
- 'Ultimate (temp, 250 GB)': 1188
+ 'Premium (team, 50 GB)': 310,
+ 'Ultimate (temp, 250 GB)': 1060
},
- RateUnit: 'USD / user'
+ RateUnit: 'CHF / user'
}
const Figshare = {
Style: 'AmountRatesCost',
Provider: 'Figshare',
Name: 'Figshare',
Url: [
{ Name: 'Figshare website', Url: 'https://figshare.com/' },
{ Name: 'Figshare Pricing', Url: 'https://www.g2.com/products/figshare/pricing' },
{ Name: 'Figshare+ Pricing', Url: 'https://knowledge.figshare.com/plus#pricing' }
],
AmountName: 'Volume',
AmountUnit: 'GB',
Adaptive: true,
ByYear: true,
AmountMin: [1, 100, 250],
AmountMax: [20, 100, 5000],
AmountStep: [1, 79, 250],
AmountFree: [0, 0, 0],
AmountFreeCumulative: false,
RateName: 'Plan',
Rates: {
'Free (up to 20 GB)': 0,
- '21-100 GB (flat rate)': 4.5,
- 'Over 100 GB': 3.5
+ '21-100 GB (flat rate)': 4.0,
+ 'Over 100 GB': 3.1
},
- RateUnit: 'USD / GB'
+ RateUnit: 'CHF / GB'
}
const Dryad = {
Style: 'CategoryAmountRatesCost',
Provider: 'Dryad',
Name: 'Dyrad',
Url: [
{ Name: 'Dryad Website Pricing', Url: 'https://datadryad.org/stash/requirements#cost' }
],
ByYear: false,
ExtraInfo: 'The costs of enabling access to research data under an SNSF grant are eligible. The data archives (data repositories) have to meet the FAIR principles.',
ExtraInfoUrl: 'http://www.snf.ch/SiteCollectionDocuments/snsf-general-implementation-regulations-for-the-funding-regulations-e.pdf#page=15',
CatName: 'Options',
Cat: {
'up to 50GB if DPC covered': 0,
- 'up to 50GB if no DPC covered': 150
+ 'up to 50GB if no DPC covered': 134
},
CatUnit: 'CHF',
AmountName: 'Storage',
AmountUnit: 'GB',
Adaptive: false,
AmountMin: 50,
AmountMax: 300,
AmountStep: 10,
AmountFree: 50,
AmountFreeCumulative: false,
RateName: 'Storage',
Rates: {
- 'Extra Storage': 5
+ 'Extra Storage': 4.5
},
RateUnit: 'CHF / GB'
}
const Acoua = {
Style: 'CategoryCost',
Provider: 'EPFL',
Name: 'ACOUA (Academic Output Archive)',
ByYear: false,
Adaptive: false,
Url: [
{ Name: 'About ACOUA', Url: 'https://www.epfl.ch/campus/library/acoua-support/' },
{ Name: 'ACOUA (access limited to EPFL network)', Url: 'http://acoua.epfl.ch' }
],
ExtraInfo: 'The ACOUA service is exclusively designed for EPFL researchers.',
CatName: 'Options',
Cat: {
'Costs covered by EPFL-DSI': 0
},
CatUnit: 'CHF'
}
// System variable definition
// ----------------------------------------------------
// ----------------------------------------------------
const NoneSelected = {
Style: 'NoneSelect',
Provider: 'None',
Name: 'Select a Provider',
Url: '',
ByYear: false
}
const UserCostSelect = {
Style: 'UserCost',
Provider: 'Manual Provider',
Name: '',
Url: '',
ByYear: false
}
// Categories definition
// ----------------------------------------------------
// ----------------------------------------------------
const storage = {
Name: 'Active Storage',
Icon: 'storage.png',
Url: [
{ Name: 'EPFL RDM software information', Url: 'https://www.epfl.ch/campus/library/services-researchers/rdm-software/' },
{ Name: 'Comparison of file synchronization software', Url: 'https://en.wikipedia.org/wiki/Comparison_of_file_synchronization_software' }
],
Data: [NoneSelected,
NasEpfl,
RcpEpfl,
MsPersonalEpfl,
MsSharedEpfl,
SwitchEpfl,
GoogleDriveEdu,
DropboxPerso,
DropboxTeam,
UserCostSelect
]
}
const ELN = {
Name: 'Electronic LabBook',
Icon: 'eln.png',
Url: [
{ Name: 'EPFL RDM software information', Url: 'https://www.epfl.ch/campus/library/services-researchers/rdm-software/' }
],
Data: [NoneSelected,
SLIMSEpfl,
ELNEpfl,
Rspace,
Benchling,
UserCostSelect
]
}
const Database = {
Name: 'Database',
Icon: 'database.png',
Url: '',
Data: [NoneSelected,
MysqlEpfl,
UserCostSelect
]
}
const datarepository = {
Name: 'Data Repository',
Icon: 'drepos.png',
Url: [
{ Name: 'EPFL RDM software information', Url: 'https://www.epfl.ch/campus/library/services-researchers/rdm-software/' }
],
Data: [
NoneSelected,
Zenodo,
Figshare,
Dryad,
UserCostSelect
]
}
const coderepository = {
Name: 'Code Repository',
Icon: 'crepos.png',
Url: '',
Data: [
NoneSelected,
C4science,
GitlabEPFL,
Github,
Bitbucket,
Gitlab,
UserCostSelect
]
}
const longermarchive = {
Name: 'Long-term Archive',
Icon: 'archive.png',
Url: '',
Data: [
NoneSelected,
Acoua,
UserCostSelect
]
}
// Combine Categories
// ----------------------------------------------------
// ----------------------------------------------------
const MainData = {
InstName: 'EPFL Library',
InstLogo: 'logo.png',
InstLogoWidth: 200,
- Updated: '2023-10-17',
+ Updated: '2023-10-24',
HelpUrl: 'mailto:researchdata@epfl.ch',
Currency: 'CHF',
OEXRApi: 'cd8d785bdb6646b0a7e4c0eba5a74199',
Conv: ['EUR', 'USD', 'GBP'],
UseStats: true,
StatsEngine: 'matomo',
StatsURL: 'costcalc.epfl.ch/matomo/',
StatsID: '1',
StatsContact: 'mailto:researchdata@epfl.ch',
- Version: 'v2.1',
+ Version: 'v2.2',
DefaultDuration: 1,
Data: [storage, ELN, Database, datarepository, coderepository, longermarchive]
}