Commit 4111a6e4 authored by Benjamin Rokseth's avatar Benjamin Rokseth
Browse files

Release 0.2.0

Could add changelog here...

Merge branch 'release/0.2.0'
parents b2d56ca2 95df6d85
......@@ -13,6 +13,40 @@ The resulting compose file can then be used with `docker-compose up -d` to provi
# Releases
## 0.2.0 (2016-11-02) First post-release!
KOHA: b8d166a4c9463aace98c372c55f466a9aea8bcaf
- services:
- add DEIC framework to records
- json-ld framing
- patron-client:
- mediatype filter
- fiction/nonfiction filter
- filter branches
- available status fix
- target audience fix
- email login
- styling
- publishe rdata
- item location
- borrower name fix
- publication publisher
- reservation postition
- reservation date
- disable IE11 transitions
- catalinker:
- numerous bugfixes
- link to patron client work
- compositiontype
- follows/followedby/partof
- work types
- koha:
- account details mail
- advance notices cronjob
- SMS sender
- send reports in cron
## 0.1.5 (2016-09-16) Bugfix release
TAG: b31510201995ee07c5edb3fc7a0ff1cb1da8abce
......
......@@ -215,6 +215,7 @@ services:
KOHA_API_PASS: "${KOHA_API_PASS}"
GITREF: "${GITREF}"
BUILD_TAG: "${BUILD_TAG}"
MARCFRAMEWORK: "DCHM"
logging:
driver: "journald"
......
......@@ -2,7 +2,7 @@ export SIP_PORT=6001
export SIP_PROXY_PORT=6002
export SIP_AUTOPASS=secret
export SIP_AUTOPASS_ENCRYPTED=encryptme
export KOHA_IMAGE_TAG=c5c98866f28ef6a41f59dd2669a70bffc5379f99
export KOHA_IMAGE_TAG=b8d166a4c9463aace98c372c55f466a9aea8bcaf
export KOHA_ADMINUSER=admin
export KOHA_ADMINPASS=secret
export KOHA_INSTANCE=name
......
......@@ -9,7 +9,7 @@ export HOST=$3
echo -e "\n Provisioning for $LSENV env, LSENV=$LSENV, LSEXTPATH=$LSEXTPATH, HOST=$HOST\n"
if [[ `uname -s` == 'Linux' && "$LSENV" != 'prod' ]]; then
echo -e "\n1) Installing Docker\n"
VERSION="1.12.2-0~$(lsb_release -c -s)"
VERSION="1.12.3-0~$(lsb_release -c -s)"
INSTALLED=`dpkg -l | grep docker-engine | awk '{print $3}'`
if [ $VERSION = "$INSTALLED" ] ; then
echo "docker version $VERSION already installed";
......
......@@ -61,7 +61,7 @@
{{#deleteResource}}
<div class="pure-g">
<div class="pure-u-1-2">
<button class="pure-button pure-button-primary next-step-button"
<button class="pure-button pure-button-primary next-step-button" tabindex="-1"
{{#if disabledUnless && checkDisabledNextStep(disabledUnless)}}disabled="disabled" title="{{disabledUnless.disabledTooltip}}"{{/if}} on-click="deleteResource:{{.}}">{{buttonLabel}}
</button>
</div>
......
......@@ -513,7 +513,6 @@ module.exports = (app) => {
rdfType: 'Publication',
label: 'Beskriv utgivelse',
reportLabel: 'Utgivelse',
showOnlyWhenInputHasValue: 'mediaTypeInput',
inputs: [
{
rdfProperty: 'mainTitle',
......@@ -1052,7 +1051,6 @@ module.exports = (app) => {
rdfType: 'Publication',
label: 'Beskriv deler',
reportLabel: 'Deler',
showOnlyWhenInputHasValue: 'mediaTypeInput',
inputs: [
{
label: 'Verk som inngår i samling',
......
......@@ -10,7 +10,7 @@
"ignoreRefs": true
}
],
"prefer-template": 1,
"prefer-template": 2,
"react/jsx-indent-props": 0,
"react/jsx-indent": 0,
"no-return-assign": 0,
......@@ -18,8 +18,8 @@
"error",
"prefer-double"
],
"no-var": 1,
"prefer-const": 1,
"no-var": 2,
"prefer-const": 2,
"prefer-arrow-callback": [
"error",
{
......
......@@ -21,6 +21,16 @@ module.exports = (app) => {
response.status(500).send(error)
}
// Remove type -> Work relations on all works, except the work in focus, to avoid
// problems when work has subjects which themselves are works.
// TODO revise this hack - it might make it difficult to present the work relations on work page.
ntdoc = ntdoc.map(el => {
if (el[ '@type' ] && el[ '@type' ].includes('http://data.deichman.no/ontology#Work') && el[ '@id' ] !== `http://data.deichman.no/work/${request.params.workId}`) {
delete el[ '@type' ]
}
return el
})
jsonld.frame(ntdoc, frame, (error, framed) => {
if (error) {
response.status(500).send(error)
......
import { replace } from 'react-router-redux'
export function toggleParameter (queryParamName, locationQuery) {
export function toggleParameter (queryParamName, inputLocationQuery) {
return (dispatch, getState) => {
const pathname = getState().routing.locationBeforeTransitions.pathname
const locationQuery = locationQuery || { ...getState().routing.locationBeforeTransitions.query }
const locationQuery = inputLocationQuery || { ...getState().routing.locationBeforeTransitions.query }
const queryParam = locationQuery[ queryParamName ]
if (queryParam !== undefined) {
delete locationQuery[ queryParamName ]
......@@ -14,10 +14,10 @@ export function toggleParameter (queryParamName, locationQuery) {
}
}
export function toggleParameterValue (queryParamName, value, locationQuery, shouldRemoveInBackString = false, nameToReplace) {
export function toggleParameterValue (queryParamName, value, inputLocationQuery, shouldRemoveInBackString = false, nameToReplace) {
return (dispatch, getState) => {
const pathname = getState().routing.locationBeforeTransitions.pathname
const locationQuery = locationQuery || { ...getState().routing.locationBeforeTransitions.query }
const locationQuery = inputLocationQuery || { ...getState().routing.locationBeforeTransitions.query }
let queryParam = locationQuery[ queryParamName ] || []
if (shouldRemoveInBackString) {
locationQuery[ queryParamName ] = queryParam.replace(`${nameToReplace}=${value}&`, '')
......
import { action } from './GenericActions'
import * as types from '../constants/ActionTypes'
export const resizeWindow = (windowWidth) => action(types.RESIZE_WINDOW, { windowWidth })
......@@ -10,7 +10,7 @@ class ClickableElement extends React.Component {
const { onClickAction, onClickArguments } = this.props
event.preventDefault()
event.stopPropagation()
onClickAction.apply(this, Array.isArray(onClickArguments) ? onClickArguments : [ onClickArguments ])
onClickAction(...Array.isArray(onClickArguments) ? onClickArguments : [ onClickArguments ])
}
render () {
......
import React, { PropTypes } from 'react'
import { injectIntl, intlShape, defineMessages, FormattedMessage, FormattedHTMLMessage } from 'react-intl'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
class Footer extends React.Component {
constructor (props) {
......@@ -15,7 +15,7 @@ class Footer extends React.Component {
render () {
return (
<footer className="main-footer">
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -64,7 +64,7 @@ class Footer extends React.Component {
</div>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
</footer>
)
}
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import { defineMessages, FormattedMessage } from 'react-intl'
import Item from './Item'
......@@ -11,7 +11,7 @@ class Items extends React.Component {
renderItems () {
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -29,7 +29,7 @@ class Items extends React.Component {
<tbody data-automation-id="work_items">
{this.props.items.map(item => <Item key={item.barcode} item={item} />)}
</tbody>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
}
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
const NonIETransitionGroup = (props) => {
if (isIe()) {
const { component, className } = props
const elementProps = { className }
Object.keys(props).forEach(prop => {
if (prop.startsWith('data-')) {
elementProps[ prop ] = props[ prop ]
}
})
return React.createElement(component, props)
} else {
return <ReactCSSTransitionGroup {...props} />
}
}
NonIETransitionGroup.propTypes = {
className: PropTypes.string.isRequired,
component: PropTypes.string.isRequired
}
export default NonIETransitionGroup
function isIe () {
return !!navigator.userAgent.match(/Trident/g) || !!navigator.userAgent.match(/MSIE/g)
}
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import { injectIntl, intlShape, defineMessages, FormattedMessage } from 'react-intl'
import Contributors from './work/fields/Contributors'
......@@ -13,7 +13,7 @@ class PublicationInfo extends React.Component {
renderItems (items) {
if (items) {
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -39,7 +39,7 @@ class PublicationInfo extends React.Component {
)
})}
</tbody>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
}
}
......@@ -82,7 +82,7 @@ class PublicationInfo extends React.Component {
render () {
const { publication, publication: { items }, intl } = this.props
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -117,7 +117,7 @@ class PublicationInfo extends React.Component {
<h2><FormattedMessage {...messages.items} /></h2>
{this.renderItems(items)}
</div>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
}
}
......
......@@ -3,7 +3,7 @@ import ReactDOM from 'react-dom'
import { injectIntl, intlShape, defineMessages, FormattedMessage } from 'react-intl'
import MediaQuery from 'react-responsive'
import firstBy from 'thenby'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import Publication from './Publication'
import PublicationInfo from './PublicationInfo'
......@@ -245,7 +245,7 @@ class Publications extends React.Component {
}
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -278,7 +278,7 @@ class Publications extends React.Component {
</h2>
</ClickableElement>
</header>
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -289,12 +289,12 @@ class Publications extends React.Component {
{collapsePublications.includes(mediaTypeFragment)
? null
: this.renderPublicationsMediaQueries(publicationHoldersByMediaType[ mediaTypeUri ].map(publicationHolder => publicationHolder.original))}
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
</section>
)
})
}
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
}
}
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import ReactDOM from 'react-dom'
import Constants from '../constants/Constants'
import { injectIntl, intlShape, defineMessages, FormattedMessage } from 'react-intl'
......@@ -81,7 +81,7 @@ class SearchFilter extends React.Component {
? `${this.props.intl.formatMessage(messages.expandGroup)} ${this.renderTitle()}`
: `${this.props.intl.formatMessage(messages.collapseGroup)} ${this.renderTitle()}`
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -104,7 +104,7 @@ class SearchFilter extends React.Component {
<ul className="searchfilters">{this.renderFilters()}</ul>
</section>,
<footer key="searchfilter_footer">{this.renderShowMore()}</footer> ]}
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
}
}
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import SearchFilterBoxItem from '../components/SearchFilterBoxItem'
import { getFiltersFromQuery } from '../utils/filterParser'
......@@ -10,7 +10,7 @@ const SearchFilterBox = ({ toggleFilter, query }) => {
: <FormattedMessage {...messages.titleSearch} />
if (getFiltersFromQuery(query).length > 0) {
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -23,7 +23,7 @@ const SearchFilterBox = ({ toggleFilter, query }) => {
{getFiltersFromQuery(query).filter((filter) => filter.active).map((filter) => <SearchFilterBoxItem
key={filter.id} filter={filter} toggleFilter={toggleFilter} />)}
</ul>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
} else {
return null
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import { Link } from 'react-router'
import { defineMessages, FormattedMessage } from 'react-intl'
import SearchFilter from './SearchFilter'
import Constants from '../constants/Constants'
class SearchFilters extends React.Component {
constructor (props) {
......@@ -12,12 +13,17 @@ class SearchFilters extends React.Component {
}
componentDidMount () {
window.addEventListener('resize', this.toggleFilterVisibility)
this.toggleFilterVisibility()
}
componentWillUpdate (nextProps) {
if (this.props.windowWidth !== nextProps.windowWidth) {
this.toggleFilterVisibility()
}
}
componentDidUpdate () {
// If a search is beeing done, check the filter visibility
// If a search is being done, check the filter visibility
if (this.props.isSearching === true) {
this.toggleFilterVisibility()
}
......@@ -33,13 +39,16 @@ class SearchFilters extends React.Component {
this.props.toggleAllFiltersVisibility()
}
toggleFilterVisibility () {
toggleFilterVisibility (event) {
if (event && event.target.innerWidth === this.props.windowWidth) {
return
}
if (window.innerWidth < 668) { // If screen size is mobile
if (this.props.locationQuery.hideFilters !== null) { // And filters are visible
if (this.props.locationQuery.hideFilters !== Constants.enabledParameter) { // And filters are visible
this.props.toggleAllFiltersVisibility() // Hide the filters
}
} else { // If screen size is tatblet or above
if (this.props.locationQuery.hideFilters === null) { // And filters are hidden
if (this.props.locationQuery.hideFilters === Constants.enabledParameter) { // And filters are hidden
this.props.toggleAllFiltersVisibility() // Show the filters
}
}
......@@ -47,7 +56,7 @@ class SearchFilters extends React.Component {
render () {
const groupedFilters = {}
const buttonClass = (this.props.locationQuery.hideFilters === null) ? 'filters-hidden' : 'filters-visible'
const buttonClass = (this.props.locationQuery.hideFilters === Constants.enabledParameter) ? 'filters-hidden' : 'filters-visible'
if (this.props.locationQuery.query && this.props.filters) {
this.props.filters.forEach(filter => {
......@@ -57,7 +66,7 @@ class SearchFilters extends React.Component {
})
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -67,7 +76,7 @@ class SearchFilters extends React.Component {
className="filters">
<div className="limit-filters">
<Link className={buttonClass} to="#" onClick={this.handleFiltersOpenClick}>
{this.props.locationQuery.hideFilters === null
{this.props.locationQuery.hideFilters === Constants.enabledParameter
? (<span>Vis filter</span>)
: (<span>Skjul filter</span>)}
</Link>
......@@ -79,7 +88,7 @@ class SearchFilters extends React.Component {
<section className="filter-wrapper"
data-automation-id="search_filters">
{this.props.locationQuery.hideFilters === null ? null : Object.keys(groupedFilters).map(aggregation => {
{this.props.locationQuery.hideFilters === Constants.enabledParameter ? null : Object.keys(groupedFilters).map(aggregation => {
const filtersByAggregation = groupedFilters[ aggregation ]
return (
<SearchFilter
......@@ -95,7 +104,7 @@ class SearchFilters extends React.Component {
)
})}
</section>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
} else {
return this.renderEmpty()
......@@ -111,7 +120,8 @@ SearchFilters.propTypes = {
toggleAllFiltersVisibility: PropTypes.func.isRequired,
toggleCollapseFilter: PropTypes.func.isRequired,
scrollTargetNode: PropTypes.object.isRequired,
isSearching: PropTypes.bool
isSearching: PropTypes.bool,
windowWidth: PropTypes.number.isRequired
}
SearchFilters.defaultProps = { filters: [] }
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import { Link } from 'react-router'
import { push } from 'react-router-redux'
import { injectIntl, intlShape, defineMessages, FormattedMessage } from 'react-intl'
......@@ -129,7 +129,7 @@ class SearchHeader extends React.Component {
const mobileNavClass = this.props.showMobileNavigation ? 'primary-mobile-menu' : 'primary-mobile-menu collapsed'
return (
<div>
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -157,7 +157,7 @@ class SearchHeader extends React.Component {
</nav>
</MediaQuery>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
<MediaQuery query="(max-width: 667px)" values={{ ...this.props.mediaQueryValues }}>
<nav className={mobileNavClass}>
......@@ -165,7 +165,7 @@ class SearchHeader extends React.Component {
</nav>
</MediaQuery>
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -195,7 +195,7 @@ class SearchHeader extends React.Component {
</div>
</form>
</div>
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
</div>
)
}
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import { Link } from 'react-router'
import { injectIntl, intlShape, defineMessages, FormattedMessage } from 'react-intl'
import Items from '../components/Items'
......@@ -44,7 +44,8 @@ class SearchResult extends React.Component {
return (
<Link data-automation-id="work-link" to={this.getResultUrl(result)}>
<h1 className="workTitle" data-automation-id="work-title">
<span className="title-text">{result.displayTitle}</span>
<span className="title-text">{result.titleLine1}</span><br />
<span className="title-text">{result.titleLine2}</span>
<span className="caret"><i className="icon-angle-wide" /></span>
</h1>
</Link>
......@@ -200,7 +201,7 @@ class SearchResult extends React.Component {
const missingCoverAltText = this.props.intl.formatMessage(messages.missingCoverImageOf, { title: result.displayTitle })
const mediaTypeURI = result.mediaTypes[ 0 ] ? result.mediaTypes[ 0 ].uri : ''
return (
<ReactCSSTransitionGroup
<NonIETransitionGroup
transitionName="fade-in"
transitionAppear
transitionAppearTimeout={500}
......@@ -253,7 +254,7 @@ class SearchResult extends React.Component {
</div>)
}
</ReactCSSTransitionGroup>
</NonIETransitionGroup>
)
}
}
......
import React, { PropTypes } from 'react'
import ReactCSSTransitionGroup from 'react-addons-css-transition-group'
import NonIETransitionGroup from './NonIETransitionGroup'
import { defineMessages, FormattedMessage } from 'react-intl'
import SearchResult from './SearchResult'
import Constants from '../constants/Constants'
......@@ -16,7 +16,7 @@ class SearchResults extends React.Component {
const from = Constants.maxSearchResultsPerPage * (this.props.page - 1)
const to = from + Constants.maxSearchResultsPerPage
return (