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] }