dspace / dspace-angular Goto Github PK
View Code? Open in Web Editor NEWDSpace 7.x (and later) User Interface built on Angular.io
Home Page: https://wiki.lyrasis.org/display/DSDOC7x/
License: BSD 3-Clause "New" or "Revised" License
DSpace 7.x (and later) User Interface built on Angular.io
Home Page: https://wiki.lyrasis.org/display/DSDOC7x/
License: BSD 3-Clause "New" or "Revised" License
The starting project doesn't lint properly. These issues should be fixed.
Before we can commit to using redux (ngrx) we need to test that it works properly in combination with angular universal
Add a component for the full Item view page
Its route should be /items/:id/full
It should contain a table that lists the key, value and language for all the Item's metadata fields, sorted alphabetically by key
Use bootstrap's responsive table styles to make the table responsive for now, we may replace it with something a little more useable on smaller screens later
It should also contain a file section that shows the following fields for each bitstream in the ORIGINAL and LICENSE bundles
It should also contain a list of the collections the item is a direct descendant of, with a link and their short description.
lodash is a transitive dependency of this project. The latest versions are no longer compatible with TypeScript versions < 2.1. At the moment this project uses TypeScript 2.0.10.
The build errors you get as a consequence look like this:
ERROR in [default] /Users/art/tmp/dspace-angular/node_modules/@types/lodash/index.d.ts:244:12
Duplicate identifier '_'.
ERROR in [default] /Users/art/tmp/dspace-angular/node_modules/@types/lodash/index.d.ts:244:15
Cannot find namespace '_'.
ERROR in [default] /Users/art/tmp/dspace-angular/node_modules/@types/lodash/index.d.ts:246:24
Cannot find name 'Partial'.
ERROR in [default] /Users/art/tmp/dspace-angular/node_modules/@types/lodash/index.d.ts:248:18
Duplicate identifier '_'.
ERROR in [default] /Users/art/tmp/dspace-angular/node_modules/@types/lodash/index.d.ts:366:38
Cannot find namespace '_'.
…
Using npm-shrinkwrap should prevent this problem for now.
If you add a new dependency and have to recreate npm-shrinkwrap.json you may run in to this again. If that dependency doesn't depend on @types/lodash > 4.15.50 but uses a range, you can safely set the @types/lodash version back to 4.15.50 in npm-shrinkwrap.json manually.
This is a placeholder ticket for future work on internationalization (i18n) for the Angular UI. Others are encouraged to add comments to this ticket on other ways to improve the translation process for the new UI.
Currently, we are using ngx-translate as our internationalization library. This uses JSON formatted translation files by default.
To simplify the translation process (for non-technical users) we may wish to use a more standard translation file format, e.g. .po
which can be used with Poedit.net. Ngx-translate already has at least to one sample po-loader.
npm run build:prod:ngc:json
will build the project for production.
node dist/server/index.js
will start the app in production.
"start:prod:node": "node dist/server/index.js",
"start:prod": "npm run build:prod:ngc:json && npm run start:prod:node",
this could work and npm run start:prod
will build and start production.
I ran in to this issue while writing tests for my reducers. I tried to reproduce in as simple a way as possible in this test branch
What happens is: if there are more than 16 tests in my spec file I get the following exception:
ERROR: 'Unhandled Promise rejection:', 'Cannot create the component AppComponent as it was not imported into the testing module!', '; Zone:', 'ProxyZone', '; Task:', 'Promise.then', '; Value:', Error{}, 'Error: Cannot create the component AppComponent as it was not imported into the testing module!
at TestBed.createComponent (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:13936:23)
at Function.TestBed.createComponent (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:13763:33)
at http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:83501:41
at ZoneDelegate.invoke (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53551:26)
at ProxyZoneSpec.onInvoke (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53215:39)
at ZoneDelegate.invoke (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53550:32)
at Zone.run (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53433:43)
at http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53821:57
at ZoneDelegate.invokeTask (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53584:35)
at ProxyZoneSpec.onInvokeTask (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53239:39)
at ZoneDelegate.invokeTask (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53583:40)
at Zone.runTask (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53473:47)
at drainMicroTaskQueue (http://localhost:9876/base/spec-bundle.js?274b278a2430fa736a07be440401dc19db37e718:53720:35)'
The tests I added are trivial and don't use any part of angular, so they shouldn't need AppComponent for anything. If there are fewer tests, everything works fine.
This also happens when you spread the tests out over multiple files, as you can see in this commit
I think this is a bug, but there could also be something wrong with my approach, as my experience with testing angular apps is limited.
Add a mechanism to configure environment variables.
This is the equivalent in the prototype however it has the downside of having the values on git. It would be better to have a mechanism where the keys can be on git, but the values remain in a file local to the environment.
Create a service to track everything that is loading.
It should have a track
method that takes an Observable<boolean>
It should offer an isLoading
Observable<boolean>
that is true when any its tracked Observables are true, false otherwise. CombineLatest is probably useful here
Afterwards, Components that are waiting for something to load should register an Observable with the LoadingService.
e.g. this.loadingService.track(this.remoteData.isLoading)
Also create an interface or class to represent a DSpaceObject. All models should implement it or inherit from it.
Keep in mind that the Collection model should represent both Communities and Collections in the DSpace backend
You can take a look at the REST API Contract on the wiki, but at the time of writing it far enough advanced yet to be more than a rough guideline
The configuration UI URL is not used within the server.ts and server.aot.ts. The node express engine binds to the port and address. It should get the values from a configuration file.
The production and development builds and tests are not dictating what environment configuration to use.
Cache time to live isn't setting anything in the server or client side cache. server.ts and server.aot.ts sets the Cache-Control per request but does not reference a configuration.
Whether or not to preboot is a property of the ngApp response. I do not see any reason to ever prevent the browser from rehydrating the universal cache set during pre-render on the server side node. For this to even make since it would have to condition on the configuration everywhere in the code where an asynchronous response is put into the universal cache.
Also, the process to get the environment configuration seems a bit more complex then necessary.
shrinkwrap is a tool built in to npm that creates a json file with the versions of all dependencies, and their dependencies, currently installed.
You add this file to git, and all subsequent npm installs will use those exact versions of dependencies, instead of the latest version in each range.
This can help ensure that everyone is working with the exact same set of pacakges, and that no issues can arise simply because a new version of a package we depend on was released.
The downside is that after you install add a new dependency to package.json, you have to run npm shrinkwrap
again. If you're not adding new dependencies nothing changes
Take a look at the one in the prototype for an example
Using redux means the application state is stored in only one place.
This means to me that components should not introduce their own state variables, but rather access the state via functions.
State variables add unnecessary complexity. They can get out of sync if they aren't managed properly - which is exactly what redux wants to avoid. With functions you're always sure to get the current state.
To illustrate what I mean I made a commit where I "fix" the header component.
This task depends on #31
In order to show when a page is loading
I'm thinking of something like this:
router-outlet-with-spinner
component, that replaces the app.component's router-outletrouter-outlet-with-spinner
component, if the service says the spinner should be active, show a spinner component, otherwise show the router-outlet$spinner-height: 4*$line-height-base;
To work against before the new REST API is far enough along.
This looks promising:
https://coligo.io/create-mock-rest-api-with-json-server/
When I launch npm install
on Windows 10 I'm getting this error
npm WARN [email protected] No license field.
npm ERR! Windows_NT 10.0.14393
npm ERR! argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install"
npm ERR! node v6.9.2
npm ERR! npm v3.10.9
npm ERR! code EBADPLATFORM
npm ERR! notsup Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})
npm ERR! notsup Valid OS: darwin
npm ERR! notsup Valid Arch: any
npm ERR! notsup Actual OS: win32
npm ERR! notsup Actual Arch: x64
I've seen that the problem doesn't occurs if the following lines are removed from npm-shrinkwrap.json
:
"fsevents": {
"version": "1.0.17",
"from": "fsevents@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.17.tgz",
"dev": true,
"optional": true,
"dependencies": {...}
},
Environment:
Steps to reproduce:
yarn run global
yarn install
yarn start
(or yarn watch
)Th result is that the server immediately dies (browser displays "The connection was reset." error and nothing is displayed). Also, the following error occurs:
Listening on: http://:::3000
Error in SSR, serving for direct CSR e {
_body:
{ Error: read ECONNRESET
at exports._errnoException (util.js:1018:11)
at TCP.onread (net.js:572:26) code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' },
status: 200,
ok: true,
statusText: 'Ok',
headers: t { _headers: Map {}, _normalizedNames: Map {} },
type: 3,
url: null }
EXCEPTION: Response with status: 200 Ok for URL: null
D:\programming\dspace-angular\node_modules\zone.js\dist\zone-node.js:158
throw error;
^
Response with status: 200 Ok for URL: null
error Command failed with exit code 1.
This error seems to be the one noted here: ngx-translate/core#362
In that ticket, the suggestion is the move UniversalModule
to load before TranslateModule
.
I tried doing that in both our node.module.ts
and browser.module.ts
. This resolves the previously mentioned error, and results in the homepage loading successfully. However, on the backend, I now see a new error:
EXCEPTION: This method is not implemented in Parse5DomAdapter: getCookie
ORIGINAL STACKTRACE:
Error: This method is not implemented in Parse5DomAdapter: getCookie
at r (D:\programming\dspace-angular\dist\server\index.js:32:15014)
at e.getCookie (D:\programming\dspace-angular\dist\server\index.js:32:28322)
at t.configureRequest (D:\programming\dspace-angular\dist\server\index.js:16:2330)
at t.createConnection (D:\programming\dspace-angular\dist\server\index.js:16:2574)
at r (D:\programming\dspace-angular\dist\server\index.js:16:2815)
at t.request (D:\programming\dspace-angular\dist\server\index.js:16:3718)
at t.get (D:\programming\dspace-angular\dist\server\index.js:16:3789)
at t.getTranslation (D:\programming\dspace-angular\dist\server\index.js:4:6657)
at t.getTranslation (D:\programming\dspace-angular\dist\server\index.js:4:7496)
at t.use (D:\programming\dspace-angular\dist\server\index.js:4:7207)
Error: This method is not implemented in Parse5DomAdapter: getCookie
at r (D:\programming\dspace-angular\dist\server\index.js:32:15014)
at e.getCookie (D:\programming\dspace-angular\dist\server\index.js:32:28322)
at t.configureRequest (D:\programming\dspace-angular\dist\server\index.js:16:2330)
at t.createConnection (D:\programming\dspace-angular\dist\server\index.js:16:2574)
at r (D:\programming\dspace-angular\dist\server\index.js:16:2815)
at t.request (D:\programming\dspace-angular\dist\server\index.js:16:3718)
at t.get (D:\programming\dspace-angular\dist\server\index.js:16:3789)
at t.getTranslation (D:\programming\dspace-angular\dist\server\index.js:4:6657)
at t.getTranslation (D:\programming\dspace-angular\dist\server\index.js:4:7496)
at t.use (D:\programming\dspace-angular\dist\server\index.js:4:7207)
This new error seems to be detailed here: angular/universal-starter#167 and the suggestion in that ticket is the list UniversalModule
last (which is the opposite of the previous suggestion which said it needs to be listed before TranslateModule
).
We should consider looking at yarn: an alternative package manager for node, designed to solve these dependency problems in a better way.
We need a way to handle pagination that can be shared between components.
Angular 4 has been released.
A little background info: Angular 3 never existed, and the step from Angular 2 to 4 is a lot smaller than the step from 1 to 2 was. It's comparable DSpace 3 in that regard. You can find the reasoning behind the change here
This blogpost gives an overview of what's new, and how to migrate.
In our case migration won't be quite as simple as it is explained in that blogpost, because of Universal. Angular Universal used to be a separate project, but is included in Angular 4 now, so our dependencies and likely also a lot of the universal specific files (server.ts, node.module.ts, browser.module.ts, …) will need to change.
Universal starter, the boilerplate project we started from, has an open issue to migrate to 4: angular/universal-starter#376
Add a collection home page
Their route should be/collections/:id
The component should show the following fields if they exist:
Create a smart component at the root that connects to the CollectionDataService to fetch the data,
Use small dumb components (i.e. a component that gets all its information through inputs rather than services) for each of the fields.
Ensure the html fields get rendered as html.
For adaptability's sake, it would be best if you'd take the approach of the simple-item-view component in the prototype, where you create a single wrapping component to render a section of the page, and then a specific component that makes use of the wrapping component, for each field on the page.
That way, if an institution using this UI later on, wants to customize the way e.g. news is rendered, they only need to touch the news component and nothing else. The wrapping component ensures that you can still re-use as much code as possible.
For the layout, I'd say base yourself on the prototype, rather than the current DSpace UIs
We need to get typedocs setup and make sure we keep up on comments.
Here is a basic typedoc.json
{
"mode": "modules",
"out": "doc",
"theme": "default",
"ignoreCompilerErrors": "true",
"experimentalDecorators": "true",
"emitDecoratorMetadata": "true",
"target": "ES5",
"moduleResolution": "node",
"preserveConstEnums": "true",
"stripInternal": "true",
"suppressExcessPropertyErrors": "true",
"suppressImplicitAnyIndexErrors": "true",
"module": "commonjs"
}
We should probably have a npm script to generate typedocs.
It would be useful to be able to run all tests at once using a single command. For example to use in Travis CI. However it should still be possible to run them separately during development.
I would also create a pree2e script that triggers webdriver:update to ensure protractor doesn't fail because webdriver:update hasn't run.
Create a component for the footer. Take a look at the prototype for an example. Note that for the prototype it was part of the AppComponent and never refactored in to its own component.
Use the same content as the prototype
Automatically set the end-year in the copyright message to the current year. That way people don't need to remember to update that i18n message every year. Angular's built-in DatePipe could be useful for this
Make it stick to the bottom using flexbox.
As it is a single-use component that is only referenced in AppComponent's template, it belongs in the CoreModule. Create that module if it doesn't exist yet.
The application runs XHR requests on the server & once again on the Client-side (when the application bootstraps)
Use a UniversalCache instead of regular Http, to save certain requests so they aren't re-ran again on the Client. (Example useage here)
https://github.com/angular/universal-starter
With redux storing a centralized state, it seems that all asynchronous requests should be put into the store and that put into Universal Cache.
JSData looks like a promising way to make it easy for us to parse JSON API responses, keeping relations intact, work with partial responses, and have caching.
We need to test if it works well with Universal and ngrx before we can commit on using it.
The style guide has been updated with recommendations about how to use modules: https://angular.io/styleguide#!#04-09
Refactor the current code to fit this structure.
Environment: Windows 10, Yarn 0.21.3, Node 6.10.1, npm 3.10.10
After running yarn start
, I see the following in the output (just before yarn run server
is triggered, near the end)
$ rollup -c rollup-server.js && rollup -c rollup-client.js
Use of `eval` (in D:\programming\dspace-angular\dist\server\index.js) is strongly discouraged, as it poses security risks and may cause
issues with minification. See https://github.com/rollup/rollup/wiki/Troubleshooting#avoiding-eval for more details
Use of `eval` (in D:\programming\dspace-angular\dist\client\main.bundle.js) is strongly discouraged, as it poses security risks and may
cause issues with minification. See https://github.com/rollup/rollup/wiki/Troubleshooting#avoiding-eval for more details
The warnings link over to this message from rollup: https://github.com/rollup/rollup/wiki/Troubleshooting#avoiding-eval
However, as I don't see any usages of eval
in our codebase, it's unclear where it is being pulled in from. Nonetheless, it seems like we should have a ticket to track this.
Do we need to bring in a dependency to deserialize JSON into objects? If so, which library should be used?
TypeScript allows for Type Assertion: https://basarat.gitbooks.io/typescript/content/docs/types/type-assertion.html
If we need a more robust deserialization, is the following library a better option?
https://github.com/pleerock/class-transformer
We are currently proposing: https://github.com/weichx/cerialize
This process will decrease the bundle size for production builds. Tree-shaking is an optimization that removes all unused exports from vendor libraries and project code.
"Universal-CLI is fork from Angular-CLI. It supports Angular Universal (with --universal flag after ung new or ung init), see Support for server side rendering for detail. It is a separate package because the Core-CLI team is not able to maintain non-core functionality."
https://github.com/devCrossNet/universal-cli#usage
"Universal-CLI is fork from Angular-CLI. It is a separate package because the Core-CLI team is not able to maintain non-core functionality."
https://github.com/angular/universal
This switch will impact many aspects of the build process, including sass, tree-shaking, tests, etc.
We probably want to wait for Angular Universal to be merged into Angular. At that time there will be many dependency upgrades and will be able to switch the build process with less changes after the upgrades.
This task depends on #30
dspace/shared/data/item/FIND_BY_ID_REQUEST
)https://angular.io/docs/ts/latest/api/core/index/OpaqueToken-class.html
The global config should be provided and injected where needed.
example
import { OpaqueToken } from '@angular/core';
export interface GlobalConfig {
API: string
}
export const DEFAULT_GLOBAL_CONFIG: GlobalConfig = {
API: 'http://localhost/dspace-api'
};
export let GLOBAL_CONFIG = new OpaqueToken('config');
Then provide it in the browser and node module
providers: [
{ provide: GLOBAL_CONFIG, useValue: DEFAULT_GLOBAL_CONFIG },
...
There will have to be adjustments to allow for configurable environment based config. Such as development, production, and test. The configurations could be in separate files and the build can decide which to provide.
Add a component for the simple Item view page
Its route should be /items/:id
For adaptability's sake, it would be best if you take inspiration from the simple-item-view component in the prototype, where you create a single wrapping component to render a section of the page, and then a specific component that makes use of the wrapping component, for each field on the page.
You could even take it a little further than the prototype, and have a sub-component to render a generic metadata-field. It takes a list of Metadatum objects as input and can have some basic configuration options that are usable for any metadata field.
e.g. by default multiple values could be separated by a line break, but if you pass in an optional separator as a component input, it is used instead
<ds-item-page-field data="item.filterMetadata('dc.contributor.author')" separator=";">…</ds-item-page-field>
The contents of the specific author component could simply look like the above example: all it does is configure the generic item-page-field component.
The reason for still creating a dedicated author component instead of configuring the generic component in the main item-page component is customizability; if an institution using this UI later on, wants to customize the way the authors is rendered, they only need to touch the author component and not the item-page component itself.
The root component should fetch the data from ItemDataService, the sub-components should be "dumb" components that get their information through component inputs rather than services.
The simple item view page should show the following fields if they exist.
dc.title as the page header
A thumbnail
bitstream.thumbnail: Bitstream
, for the primary bitstream in the ORIGINAL bundle. In older DSpaces the logic for deciding which file to use as thumbnail was part of the theme, I'd like to move that to the REST API if at all possible.The file section
The date:
The authors
The abstract
The URI
The collections the item is a direct descendant of, as links
If the current mock data doesn't contain a value for any of these metadata fields, feel free to add it.
GET
call to /api/collections/
)The next version of ngrx will combine their most commonly used separate modules in to a single module: platform. It will bring their versions in sync with Angular's. It hasn't been released yet.
There will be a few breaking changes. Nothing problematic for us at first sight. Here is the migration guide
Add ngrx-store-freeze as a dev-dependency and enable it only in development mode.
When running build locally on Windows 10 postcss script generates a command not found
error.
It works properly on Unix like OS.
It's possible to solve it adding node
command to the script.
We agreed on using:
These tools need to be added to the project and configured.
We'll also need some documentation added to the wiki on how to use them (e.g. create a my.component.spec
file in the same directory as the component for jasmine, put your e2e tests in that folder, that sort of thing…)
The script "start:dev" should have the command 'npm run server:dev' not 'npm run server' or the execution will fail.
Some npm scripts won't work unless certain dependencies are installed globally. webpack-bundle-size-analyzer
is one such example. We need to identify the others, and add an npm script to install them.
A basic header, footer and navigation. Nothing fancy or overly configurable at the moment.
Just the first basic framework for the UI.
postcss allows us to add a number of plugins that perform actions on the css, after it has been converted by sass
The most important such plugin is autoprefixer. It allows you to write plain css without having to worry about browser specific prefixes. You specify in your autoprefixer config how many browser versions you want to support (e.g. 'last 2 versions'
) and autoprefixer does the rest.
Bootstrap 4 was written with autoprefixer in mind, so as we're converting bootstrap's sass to css ourselves we'll need to add autoprefixer as well.
The conversation in the PR that added bootstrap may be useful
Tslint and codelyzer were added to the project, but currently you have to manually run them.
There's probably a webpack loader to run them every time webpack builds. We should add that
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.