diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2021-03-10 13:44:13 +0100 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2021-03-10 13:44:13 +0100 |
| commit | 0e849395aab06b3c05b609740ebc94cf3a5cd258 (patch) | |
| tree | 2efeee477043d7d3180047932231aef13dff1b9a /animism-align | |
| parent | 554695be3d2c0ed122fa83b6b0ac76e338116268 (diff) | |
navigating around, fix api filtering, add episode stats
Diffstat (limited to 'animism-align')
13 files changed, 105 insertions, 24 deletions
diff --git a/animism-align/cli/app/controllers/annotation_controller.py b/animism-align/cli/app/controllers/annotation_controller.py index aed7310..78947a8 100644 --- a/animism-align/cli/app/controllers/annotation_controller.py +++ b/animism-align/cli/app/controllers/annotation_controller.py @@ -9,8 +9,16 @@ from app.controllers.crud_controller import CrudView class AnnotationView(CrudView): model = Annotation form = AnnotationForm + index_all = False + use_limit = False default_sort = "start_ts" + def where(self, query, args): + episode_id = args.get('episode_id', default=None) + if episode_id is not None: + query = query.filter(Annotation.episode_id == int(episode_id)) + return query + def on_create(self, session, form, item): if 'paragraph_id' in form: item.paragraph_id = form['paragraph_id'] @@ -46,8 +54,15 @@ class AnnotationView(CrudView): session.close() return { 'status': 'error', 'error': 'duration is invalid '} + try: + episode_id = float(request.json['episode_id']) + except: + print("Annotation splice: episode_id is undefined") + session.close() + return { 'status': 'error', 'error': 'episode_id is invalid '} + query = session.query(self.model) - query = query.filter(Annotation.start_ts > start_ts) + query = query.filter(Annotation.start_ts > start_ts, Annotation.episode_id == episode_id) items = query.all() print(f"{len(items)} annotations would be updated") diff --git a/animism-align/cli/app/controllers/crud_controller.py b/animism-align/cli/app/controllers/crud_controller.py index 29a570a..ace84f3 100644 --- a/animism-align/cli/app/controllers/crud_controller.py +++ b/animism-align/cli/app/controllers/crud_controller.py @@ -11,6 +11,7 @@ class CrudView(FlaskView): # model = Collection # form = CollectionForm index_all = True + use_limit = True excluded_methods = ['on_index', 'on_show', 'on_create', 'on_update', 'on_destroy'] default_sort = "id" default_order = "asc" @@ -46,7 +47,10 @@ class CrudView(FlaskView): query = query.order_by(order_by, order_by_id) else: query = query.order_by(order_by) - items = query.offset(offset).limit(limit).all() + if self.use_limit: + items = query.offset(offset).limit(limit).all() + else: + items = query.all() res = self.on_index(session, { 'status': 'ok', diff --git a/animism-align/cli/app/controllers/media_controller.py b/animism-align/cli/app/controllers/media_controller.py index e7e620c..77f7ac2 100644 --- a/animism-align/cli/app/controllers/media_controller.py +++ b/animism-align/cli/app/controllers/media_controller.py @@ -9,6 +9,14 @@ from app.controllers.crud_controller import CrudView class MediaView(CrudView): model = Media form = MediaForm + index_all = False + use_limit = False + + def where(self, query, args): + episode_id = args.get('episode_id', default=None) + if episode_id is not None: + query = query.filter(Media.episode_id == int(episode_id)) + return query def on_create(self, session, form, item): if 'settings' in form: diff --git a/animism-align/cli/app/controllers/paragraph_controller.py b/animism-align/cli/app/controllers/paragraph_controller.py index 807135d..9e6d4bc 100644 --- a/animism-align/cli/app/controllers/paragraph_controller.py +++ b/animism-align/cli/app/controllers/paragraph_controller.py @@ -9,8 +9,16 @@ from app.controllers.crud_controller import CrudView class ParagraphView(CrudView): model = Paragraph form = ParagraphForm + index_all = False + use_limit = False default_sort = "start_ts" + def where(self, query, args): + episode_id = args.get('episode_id', default=None) + if episode_id is not None: + query = query.filter(Paragraph.episode_id == int(episode_id)) + return query + def on_create(self, session, form, item): if 'settings' in form: item.settings = form['settings'] diff --git a/animism-align/cli/app/settings/app_cfg.py b/animism-align/cli/app/settings/app_cfg.py index ceb9e43..6d5f4c0 100644 --- a/animism-align/cli/app/settings/app_cfg.py +++ b/animism-align/cli/app/settings/app_cfg.py @@ -76,6 +76,13 @@ HASH_BRANCH_SIZE = 3 # for sha256 subdirs USE_SQLITE = os.getenv("USE_SQLITE") == "True" # ----------------------------------------------------------------------------- +# APIs +# ----------------------------------------------------------------------------- + +DEFAULT_LIMIT = 50 +MAX_LIMIT = 1000 + +# ----------------------------------------------------------------------------- # S3 storage # ----------------------------------------------------------------------------- @@ -85,7 +92,7 @@ except Exception as e: pass # ----------------------------------------------------------------------------- -# Le crypto +# Le crypto~ # ----------------------------------------------------------------------------- TOKEN_SECRET = os.getenv("TOKEN_SECRET") or None diff --git a/animism-align/frontend/app/api/crud.fetch.js b/animism-align/frontend/app/api/crud.fetch.js index ddcd80b..348f97f 100644 --- a/animism-align/frontend/app/api/crud.fetch.js +++ b/animism-align/frontend/app/api/crud.fetch.js @@ -45,7 +45,7 @@ export function crud_fetch(type, tag) { function _get_url(_url, data) { const url = new URL(window.location.origin + _url) if (data) { - Object.keys(data).forEach(key => url.searchParams.append(key, data[key])) + Object.keys(data).forEach(key => url.searchParams.set(key, data[key])) } return url } diff --git a/animism-align/frontend/app/common/table.component.js b/animism-align/frontend/app/common/table.component.js index b26dcba..eada263 100644 --- a/animism-align/frontend/app/common/table.component.js +++ b/animism-align/frontend/app/common/table.component.js @@ -4,7 +4,7 @@ import { formatName } from 'app/utils' const __HR__ = '__HR__' -export function TableObject({ tag, object, order, summary }) { +export function TableObject({ tag, object, order, summary, className }) { if (!object) return null if (object === 'loading') { return <div className='tableObject loading'>{tag}{': Loading'}</div> @@ -37,7 +37,7 @@ export function TableObject({ tag, object, order, summary }) { return ( <div> {tag && <h3 className='tt'>{tag}</h3>} - <table className={'tableObject ' + tag}> + <table className={'tableObject ' + (className || "")}> <tbody> {objects.map((key, i) => ( <TableRow key={key + '_' + i} name={key} value={object[key]} /> diff --git a/animism-align/frontend/app/views/editor/editor.gate.js b/animism-align/frontend/app/views/editor/editor.gate.js index 5076350..87ca367 100644 --- a/animism-align/frontend/app/views/editor/editor.gate.js +++ b/animism-align/frontend/app/views/editor/editor.gate.js @@ -6,9 +6,12 @@ import { Loader } from 'app/common' import actions from 'app/actions' class EditorGate extends Component { + state = { + ready: false, + } + constructor(props) { super(props) - this.load() } componentDidMount() { @@ -30,13 +33,17 @@ class EditorGate extends Component { if (!this.props.episode.lookup) return if (!this.props.episode_id) return if (parseInt(this.props.episode_id) === parseInt(this.props.current_episode_id)) return + this.setState({ ready: false }) const episode = this.props.episode.lookup[this.props.episode_id] const project = this.props.project.lookup[episode.project_id] actions.site.loadEpisode(project, episode) + .then(() => { + this.setState({ ready: true }) + }) } render() { - if (parseInt(this.props.episode_id) === parseInt(this.props.current_episode_id)) { + if (this.state.ready && parseInt(this.props.episode_id) === parseInt(this.props.current_episode_id)) { return this.props.children } return ( @@ -48,7 +55,7 @@ class EditorGate extends Component { const mapStateToProps = state => ({ episode: state.episode.index, project: state.project.index, - current_episode_id: state.site.episode.id, + current_episode_id: state.site.episode ? state.site.episode.id : 0, }) export default connect(mapStateToProps)(EditorGate)
\ No newline at end of file diff --git a/animism-align/frontend/app/views/editor/overview/overview.container.js b/animism-align/frontend/app/views/editor/overview/overview.container.js index b06a299..d64bd9f 100644 --- a/animism-align/frontend/app/views/editor/overview/overview.container.js +++ b/animism-align/frontend/app/views/editor/overview/overview.container.js @@ -7,11 +7,11 @@ import './overview.css' // import actions from 'app/actions' import { Loader, TableObject } from 'app/common' import { groupResponseBy } from 'app/utils/api.utils' -import { courtesyS, formatDateTime } from 'app/utils' +import { courtesyS, formatDateTime, timestampHMS } from 'app/utils' class OverviewContainer extends Component { state = { - ready: true, + ready: false, } constructor(props) { @@ -29,14 +29,26 @@ class OverviewContainer extends Component { } build() { - // const episodes = groupResponseBy(this.props.episodes, 'project_id') - // const venues = groupResponseBy(this.props.venues, 'project_id') - // this.setState({ ready: true, episodes, venues }) + const { annotation } = this.props + const stats = annotation.order.reduce((stats, annotation_id) => { + const { paragraph_id, type } = annotation.lookup[annotation_id] + if (paragraph_id) { + stats.paragraphs[paragraph_id] = true + } + if (!stats.types[type]) { + stats.types[type] = 0 + } + stats.types[type] += 1 + return stats + }, { types: {}, paragraphs: {} }) + setTimeout(() => { + this.setState({ ready: true, stats }) + }, 20) } render() { - const { project, episode, media, annotation, align } = this.props - const { ready } = this.state + const { project, episode, media, annotation, align, viewer } = this.props + const { ready, stats } = this.state if (!ready) { return ( <div className='overview'> @@ -44,8 +56,7 @@ class OverviewContainer extends Component { </div> ) } - // console.log(this.props) - console.log(annotation.order.length) + return ( <div className='overview'> <div className='project-top'> @@ -53,15 +64,21 @@ class OverviewContainer extends Component { <h1>{`${project.title}: Episode ${episode.episode_number}`}</h1> <h2>{episode.title}</h2> </div> - <h3>Statistics</h3> - <TableObject - className="overview" + tag="Overview" order={"annotations".split(" ")} object={{ annotations: courtesyS(annotation.order.length, 'annotation'), + media: media.order.length + ' media', + sections: courtesyS(viewer.sections.length, 'section'), + paragraphs: courtesyS(Object.keys(stats.paragraphs).length, 'paragraph'), + duration: timestampHMS(align.duration), }} /> + <TableObject + tag="Annotations" + object={stats.types} + /> </div> </div> ) @@ -73,6 +90,7 @@ const mapStateToProps = state => ({ episode: state.site.episode, media: state.media.index, annotation: state.annotation.index, + viewer: state.viewer, align: state.align, }) diff --git a/animism-align/frontend/app/views/editor/overview/overview.css b/animism-align/frontend/app/views/editor/overview/overview.css index 2c8b903..6a6e292 100644 --- a/animism-align/frontend/app/views/editor/overview/overview.css +++ b/animism-align/frontend/app/views/editor/overview/overview.css @@ -5,3 +5,11 @@ .overview h2 { margin: 0.5rem 0 1rem 0; } + +.overview .tableObject th, .overview .tableTuples th { + color: #ddd; +} + +.overview .tableObject td { + color: #eee; +}
\ No newline at end of file diff --git a/animism-align/frontend/app/views/nav/header.component.js b/animism-align/frontend/app/views/nav/header.component.js index 8443278..4e43657 100644 --- a/animism-align/frontend/app/views/nav/header.component.js +++ b/animism-align/frontend/app/views/nav/header.component.js @@ -14,7 +14,7 @@ function Header(props) { return null } if (props.router.location.pathname.match("/editor")) { - const episode_id = props.router.location.pathname.split('/')[1] + const episode_id = props.router.location.pathname.split('/')[2] return ( <header> <div> diff --git a/animism-align/frontend/app/views/site/site.actions.js b/animism-align/frontend/app/views/site/site.actions.js index a9d3deb..ac14096 100644 --- a/animism-align/frontend/app/views/site/site.actions.js +++ b/animism-align/frontend/app/views/site/site.actions.js @@ -20,17 +20,18 @@ export const loadSite = () => dispatch => { export const loadEpisode = (project, episode) => dispatch => { const { id: episode_id } = episode dispatch({ type: types.editor.loading }) - Promise.all([ + return Promise.all([ // actions.site.loadText(episode), actions.site.loadPeaks(episode), actions.audio.load(episode), actions.annotation.index({ episode_id }), actions.paragraph.index({ episode_id }), actions.media.index({ episode_id }), - ]).then(() => { + ]).then((results) => { actions.viewer.loadSections() dispatch({ type: types.editor.loaded, project, episode }) console.log('Episode loaded') + return results }).catch(err => { console.error(err) }) diff --git a/animism-align/frontend/app/views/viewer/viewer.actions.js b/animism-align/frontend/app/views/viewer/viewer.actions.js index ef98533..a2764ed 100644 --- a/animism-align/frontend/app/views/viewer/viewer.actions.js +++ b/animism-align/frontend/app/views/viewer/viewer.actions.js @@ -48,6 +48,11 @@ export const loadSections = () => dispatch => { const { order: annotationOrder, lookup: annotationLookup } = state.annotation.index const { lookup: mediaLookup } = state.media.index + if (annotationOrder.length === 0) { + dispatch({ type: types.viewer.load_sections, sections: [], footnoteList: [] }) + return + } + // console.log(state) // loop over the annotations in time order. |
