mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2026-09-09 18:02:54 +00:00
+1
-1
@@ -89,7 +89,7 @@
|
||||
"component": {},
|
||||
"serve": {
|
||||
"proxyConfig": "proxy.conf.js",
|
||||
"port": 3000,
|
||||
"port": 4200,
|
||||
"host": "0.0.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
version: 2
|
||||
jobs:
|
||||
build:
|
||||
working_directory: ~/alfresco-content-app
|
||||
docker:
|
||||
- image: circleci/node:8-browsers
|
||||
steps:
|
||||
- checkout
|
||||
- restore_cache:
|
||||
key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }}
|
||||
- run: npm install
|
||||
- save_cache:
|
||||
key: alfresco-content-app-{{ .Branch }}-{{ checksum "package.json" }}
|
||||
paths:
|
||||
- "node_modules"
|
||||
- run: xvfb-run -a npm run test:ci
|
||||
@@ -0,0 +1,11 @@
|
||||
.circleci
|
||||
.git
|
||||
.github
|
||||
.vscode
|
||||
coverage
|
||||
docs
|
||||
e2e
|
||||
e2e-output
|
||||
node_modules
|
||||
scripts
|
||||
src
|
||||
@@ -0,0 +1,5 @@
|
||||
ALFRESCO_TAG=6.0.4-ea
|
||||
SHARE_TAG=6.0.a
|
||||
SOLR6_TAG=1.1.0
|
||||
POSTGRES_TAG=10.1
|
||||
ACA_TAG=development
|
||||
@@ -0,0 +1,53 @@
|
||||
<!--
|
||||
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
|
||||
|
||||
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
|
||||
-->
|
||||
|
||||
## I'm submitting a...
|
||||
<!-- Check one of the following options with "x" -->
|
||||
<pre><code>
|
||||
[ ] Regression (a behavior that used to work and stopped working in a new release)
|
||||
[ ] Bug report <!-- Please search GitHub for a similar issue or PR before submitting -->
|
||||
[ ] Feature request
|
||||
[ ] Documentation issue or request
|
||||
[ ] Support request => Please do not submit support request here, instead see https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md#question
|
||||
</code></pre>
|
||||
|
||||
## Current behavior
|
||||
<!-- Describe how the issue manifests. -->
|
||||
|
||||
|
||||
## Expected behavior
|
||||
<!-- Describe what the desired behavior would be. -->
|
||||
|
||||
|
||||
## Minimal reproduction of the problem with instructions
|
||||
<!--
|
||||
For bug reports please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem.
|
||||
-->
|
||||
|
||||
## What is the motivation / use case for changing the behavior?
|
||||
<!-- Describe the motivation or the concrete use case. -->
|
||||
|
||||
|
||||
## Environment
|
||||
|
||||
<pre><code>
|
||||
ACA version: X.Y.Z
|
||||
<!-- Check whether this is still an issue in the most recent ACA version -->
|
||||
|
||||
Browser:
|
||||
- [ ] Chrome version XX
|
||||
- [ ] Firefox version XX
|
||||
- [ ] Safari version XX
|
||||
- [ ] Edge version XX
|
||||
- [ ] IE11
|
||||
|
||||
For Tooling issues:
|
||||
- Node version: XX <!-- run `node --version` -->
|
||||
- Platform: <!-- Mac, Linux, Windows -->
|
||||
|
||||
Others:
|
||||
<!-- Anything else relevant? Operating system version, IDE, package manager, HTTP server, ... -->
|
||||
</code></pre>
|
||||
@@ -0,0 +1,43 @@
|
||||
## PR Checklist
|
||||
Please check if your PR fulfills the following requirements:
|
||||
|
||||
- [ ] The commit message follows our guidelines: https://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md#commit
|
||||
- [ ] Tests for the changes have been added (for bug fixes / features)
|
||||
- [ ] Docs have been added / updated (for bug fixes / features)
|
||||
|
||||
|
||||
## PR Type
|
||||
What kind of change does this PR introduce?
|
||||
|
||||
<!-- Please check the one that applies to this PR using "x". -->
|
||||
```
|
||||
[ ] Bugfix
|
||||
[ ] Feature
|
||||
[ ] Code style update (formatting, local variables)
|
||||
[ ] Refactoring (no functional changes, no api changes)
|
||||
[ ] Build related changes
|
||||
[ ] CI related changes
|
||||
[ ] Documentation content changes
|
||||
[ ] Application / Infrastructure changes
|
||||
[ ] Other... Please describe:
|
||||
```
|
||||
|
||||
## What is the current behavior?
|
||||
<!-- Please describe the current behavior that you are modifying, or link to a relevant issue. -->
|
||||
|
||||
Issue Number: N/A
|
||||
|
||||
|
||||
## What is the new behavior?
|
||||
|
||||
|
||||
## Does this PR introduce a breaking change?
|
||||
```
|
||||
[ ] Yes
|
||||
[ ] No
|
||||
```
|
||||
|
||||
<!-- If this PR contains a breaking change, please describe the impact and migration path for existing applications below. -->
|
||||
|
||||
|
||||
## Other information
|
||||
@@ -24,6 +24,7 @@
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
|
||||
+3
-23
@@ -5,29 +5,9 @@ language: node_js
|
||||
node_js:
|
||||
- "8"
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- ./node_modules
|
||||
|
||||
services:
|
||||
- docker
|
||||
|
||||
install:
|
||||
- npm install
|
||||
- npm install -g npm@latest
|
||||
- npm ci
|
||||
|
||||
script:
|
||||
- npm run build
|
||||
- npm run test -- --single-run --no-progress && cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage && rm -rf ./coverage
|
||||
|
||||
# Send coverage data to codecov
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash) -X gcov
|
||||
- export BRANCH=$(if [ "$TRAVIS_PULL_REQUEST" == "false" ]; then echo $TRAVIS_BRANCH; else echo $TRAVIS_PULL_REQUEST_BRANCH; fi)
|
||||
- echo "TRAVIS_BRANCH=$TRAVIS_BRANCH, PR=$PR, BRANCH=$BRANCH"
|
||||
- export TAG=`if [ "$BRANCH" == "master" ]; then echo "latest"; else echo $BRANCH ; fi`
|
||||
- sed -i 's/{:port}/:8080/1' ./dist/app.config.json
|
||||
- docker build -t $DOCKER_REPO:$TAG .
|
||||
# Publish extra image based on Travis build number
|
||||
- docker tag $DOCKER_REPO:$TAG $DOCKER_REPO:travis-$TRAVIS_BUILD_NUMBER
|
||||
- docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"
|
||||
- docker push $DOCKER_REPO
|
||||
- npm run test:ci
|
||||
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"sidenav"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# Contributor Code of Conduct
|
||||
|
||||
We want to make everyone feel welcome to contribute to ACA.
|
||||
We promise to respect everyone who posts issues, updates documentation,
|
||||
submits pull requests, provides feedback in comments, or makes any other contribution to the project.
|
||||
|
||||
We expect all discussion about the project (on GitHub, social media and other channels) to be positive and constructive.
|
||||
We do not accept personal attacks, trolling, public or private harassment, insults,
|
||||
or other unprofessional conduct towards anyone.
|
||||
|
||||
We promise to show respect to all contributors regardless of their gender, gender identity,
|
||||
sexual orientation, disability, age, race, ethnicity, religion, or level of experience.
|
||||
|
||||
We expect all contributors to understand and follow these standards
|
||||
If any member of the community does not follow the code of conduct,
|
||||
the maintainers will do whatever they consider appropriate to stop the unacceptable behavior.
|
||||
This may include removing issues, comments, and PRs or blocking accounts.
|
||||
Any bans may be temporary or permanent, at the maintainers’ discretion.
|
||||
|
||||
Contact us if you see any behavior that breaks the code of conduct, whether it is directed at you or at anyone else.
|
||||
We take responsibility for making sure the code of conduct is clear and understandable,
|
||||
so you should also contact us if you think there is anything that needs to be explained better.
|
||||
Our contact email address is: [conduct@alfresco.com](mailto:conduct@alfresco.com)
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
# Contributing to Alfresco Content Application (ACA)
|
||||
|
||||
Alfresco actively encourages external contributions to this Content Application so that the project can move develop in such a way that benefits the wider community.
|
||||
|
||||
As a contributor, here are the guidelines we would like you to follow:
|
||||
|
||||
* [Code of Conduct](#coc)
|
||||
* [Question or Problem?](#question)
|
||||
* [Issues and Bugs](#issue)
|
||||
* [Feature Requests](#feature)
|
||||
* [Submission Guidelines](#submit)
|
||||
* [Coding Rules](#rules)
|
||||
* [Signing the CLA](#cla)
|
||||
|
||||
## <a name="coc"></a> Code of Conduct
|
||||
|
||||
Help us keep Alfresco Content Application open and inclusive.
|
||||
Please read and follow our [Code of Conduct][coc].
|
||||
|
||||
## <a name="question"></a> Got a Question or Problem?
|
||||
|
||||
Please do not open issues for general support questions as we want to keep GitHub issues for bug reports and feature requests.
|
||||
|
||||
The ADF [Gitter][gitter] channel is a much better place to ask questions:
|
||||
|
||||
* direct access to many experienced Angular and ADF developers
|
||||
* questions and answers stay available for public viewing so your question / answer might help someone else
|
||||
* all discussions are saved and indexed, you can search for previous answers
|
||||
|
||||
## <a name="issue"></a> Found a Bug?
|
||||
|
||||
If you find a bug in the source code, you can help us by:
|
||||
|
||||
* [submitting an issue](#submit-issue) to our [ACA JIRA project][jira]
|
||||
* [submitting an issue](#submit-issue) to our [GitHub Repository][github].
|
||||
|
||||
Even better, [submit a Pull Request](#submit-pr) with a fix.
|
||||
|
||||
## <a name="feature"></a> Missing a Feature?
|
||||
|
||||
You can *request* a new feature by [submitting an issue](#submit-issue)
|
||||
to our [JIRA project][jira] or GitHub Repository.
|
||||
If you would like to *implement* a new feature, please submit an issue with a proposal for your work first,
|
||||
to be sure that we can use it.
|
||||
|
||||
Please consider what kind of change it is:
|
||||
|
||||
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
|
||||
discussed. This will also allow us to better coordinate our efforts, prevent duplication of work,
|
||||
and help you to craft the change so that it is successfully accepted into the project.
|
||||
* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr).
|
||||
|
||||
## <a name="submit"></a> Submission Guidelines
|
||||
|
||||
Before you submit an issue, search the issue tracker, an issue for your problem may already exist
|
||||
and the discussion might inform you of potential workarounds.
|
||||
|
||||
We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it.
|
||||
In order to reproduce bugs, we require you to provide a description of the problem, steps to reproduce and other supporting information that will help us recreate the problem you experianced.
|
||||
|
||||
Having a reproducible scenario gives us a wealth of important information without going back & forth to you with additional questions like:
|
||||
|
||||
* version of node.js used
|
||||
* version of NPM used
|
||||
* version of Angular used
|
||||
* versions of ADF libraries used
|
||||
* 3rd-party libraries and their versions
|
||||
* and most importantly - a use-case that fails
|
||||
|
||||
You can file new issues by filling out our [new issue form](https://github.com/Alfresco/alfresco-content-app/issues/new).
|
||||
|
||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||
|
||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
|
||||
1. Search [GitHub](https://github.com/Alfresco/alfresco-content-app/pulls) for an open or closed PR
|
||||
that relates to your submission. You don't want to duplicate effort.
|
||||
1. Sign the [Contributor License Agreement (CLA)](#cla) before sending PRs.
|
||||
We cannot accept code without this.
|
||||
Make sure you sign with the primary email address of the Git identity that has been granted access to the Angular repository.
|
||||
1. Fork the ACA repository.
|
||||
1. Make your changes in a new git branch based on **development**:
|
||||
|
||||
```shell
|
||||
git checkout -b my-fix-branch development
|
||||
```
|
||||
|
||||
1. Create your patch, **including appropriate test cases**.
|
||||
1. Follow our [Coding Rules](#rules).
|
||||
1. Run the full ACA test suite and ensure that all tests pass.
|
||||
1. Commit your changes using a descriptive commit message.
|
||||
1. Push your branch to GitHub:
|
||||
|
||||
```shell
|
||||
git push origin my-fix-branch
|
||||
```
|
||||
|
||||
1. In GitHub, send a pull request to `alfresco-content-app:development`.
|
||||
* If we suggest changes then:
|
||||
* Make the required updates.
|
||||
* Re-run the ACA test suites to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
|
||||
```shell
|
||||
git rebase development -i
|
||||
git push -f
|
||||
```
|
||||
|
||||
That's it! Thank you for your contribution!
|
||||
|
||||
## <a name="rules"></a> Coding Rules
|
||||
|
||||
To ensure consistency throughout the source code, keep these rules in mind as you are working:
|
||||
|
||||
* All features or bug fixes **must be tested** by one or more specs (unit-tests).
|
||||
* All public API methods **must be documented**.
|
||||
|
||||
## <a name="cla"></a> Signing the CLA
|
||||
|
||||
Sign the [Contributor License Agreement (CLA)][cla] before sending pull requests.
|
||||
In addition, you will get the CLA link automatically generated for your first pull request.
|
||||
|
||||
For any code changes to be accepted, the CLA must be signed.
|
||||
|
||||
<hr>
|
||||
|
||||
If you have more than one Git identity, you must make sure that you sign the CLA using the primary
|
||||
email address associated with the ID that has been granted access to the Angular repository.
|
||||
Git identities can be associated with more than one email address, and only one is primary.
|
||||
|
||||
Here are some links to help you sort out multiple Git identities and email addresses:
|
||||
|
||||
* https://help.github.com/articles/setting-your-commit-email-address-in-git/
|
||||
* https://stackoverflow.com/questions/37245303/what-does-usera-committed-with-userb-13-days-ago-on-github-mean
|
||||
* https://help.github.com/articles/about-commit-email-addresses/
|
||||
* https://help.github.com/articles/blocking-command-line-pushes-that-expose-your-personal-email-address/
|
||||
|
||||
Note that if you have more than one Git identity, it is important to verify that you are logged in
|
||||
with the same ID with which you signed the CLA, before you commit changes. If not, your PR will fail the CLA check.
|
||||
|
||||
<hr>
|
||||
|
||||
[coc]: https://github.com/Alfresco/alfresco-content-app/blob/master/CODE_OF_CONDUCT.md
|
||||
[github]: https://github.com/Alfresco/alfresco-content-app
|
||||
[gitter]: https://gitter.im/Alfresco/alfresco-ng2-components
|
||||
[jira]: https://issues.alfresco.com/jira/projects/ACA
|
||||
[cla]: https://cla-assistant.io/Alfresco/alfresco-content-app
|
||||
@@ -1,4 +1,6 @@
|
||||
FROM nginx:alpine
|
||||
LABEL version="1.2"
|
||||
LABEL maintainer="Denys Vuika <denys.vuika@alfresco.com>"
|
||||
|
||||
COPY nginx.conf /etc/nginx/nginx.conf
|
||||
|
||||
|
||||
@@ -27,18 +27,21 @@ please include a clear description, steps to reproduce and screenshots where app
|
||||
All issues will be reviewed; bugs will be categorized if reproducible and enhancement/feature suggestions
|
||||
will be considered against existing priorities if the use case serves a general-purpose need.
|
||||
|
||||
## Want to help?
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent!
|
||||
Read up on our guidelines for [contributing][contributing]
|
||||
and then check out one of our issues in the [Jira][jira] or [GitHub][github]
|
||||
|
||||
## Development server
|
||||
|
||||
Run `npm start` for a dev server. Navigate to `http://localhost:3000/` (opens by default).
|
||||
Run `npm start` for a dev server. Navigate to `http://localhost:4200/` (opens by default).
|
||||
The app will automatically reload if you change any of the source files.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.
|
||||
Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
Use the `--prod` flag for a production build.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
@@ -48,25 +51,10 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.
|
||||
|
||||
Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).
|
||||
|
||||
## Running documentation locally
|
||||
|
||||
For development purposes, you can run and test documentation locally.
|
||||
That is useful when working in different branches instead of a `master` one.
|
||||
|
||||
Run the following command to install the lightweight development server [wsrv](https://denysvuika.gitlab.io/wsrv/#/):
|
||||
|
||||
```sh
|
||||
npm install -g wsrv
|
||||
```
|
||||
|
||||
Now you can use the next command to serve the documentation folder in the browser:
|
||||
|
||||
```sh
|
||||
wsrv docs/ -s -l -o
|
||||
```
|
||||
|
||||
The browser page is going to automatically reload upon changes.
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
|
||||
[contributing]: ttps://github.com/Alfresco/alfresco-content-app/blob/master/CONTRIBUTING.md
|
||||
[github]: https://github.com/Alfresco/alfresco-content-app/issues
|
||||
[jira]: https://issues.alfresco.com/jira/projects/ACA
|
||||
|
||||
+91
-4
@@ -1,8 +1,95 @@
|
||||
version: '3.1'
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
app:
|
||||
image: 'alfresco/content-app'
|
||||
build: '.'
|
||||
alfresco:
|
||||
image: alfresco/alfresco-content-repository-community:${ALFRESCO_TAG}
|
||||
depends_on:
|
||||
- postgres
|
||||
environment:
|
||||
CATALINA_OPTS : "
|
||||
-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
|
||||
"
|
||||
JAVA_OPTS : "
|
||||
-Ddb.driver=org.postgresql.Driver
|
||||
-Ddb.username=alfresco
|
||||
-Ddb.password=alfresco
|
||||
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
|
||||
-Dsolr.host=solr6
|
||||
-Dsolr.port=8983
|
||||
-Dsolr.secureComms=none
|
||||
-Dsolr.base.url=/solr
|
||||
-Dindex.subsystem.name=solr6
|
||||
"
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8080:8080 #Browser port
|
||||
- 8000:8000 #Debug port
|
||||
|
||||
share:
|
||||
image: alfresco/alfresco-share:${SHARE_TAG}
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
- REPO_HOST=alfresco
|
||||
- REPO_PORT=8080
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8081:8080
|
||||
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_TAG}
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=alfresco
|
||||
- POSTGRES_USER=alfresco
|
||||
- POSTGRES_DB=alfresco
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 5432:5432
|
||||
|
||||
solr6:
|
||||
image: alfresco/alfresco-search-services:${SOLR6_TAG}
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
#Solr needs to know how to register itself with Alfresco
|
||||
- SOLR_ALFRESCO_HOST=alfresco
|
||||
- SOLR_ALFRESCO_PORT=8080
|
||||
#Alfresco needs to know how to call solr
|
||||
- SOLR_SOLR_HOST=solr6
|
||||
- SOLR_SOLR_PORT=8983
|
||||
#Create the default alfresco and archive cores
|
||||
- SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8983:8983 #Browser port
|
||||
|
||||
content-app:
|
||||
image: alfresco/alfresco-content-app:${ACA_TAG}
|
||||
build: .
|
||||
depends_on:
|
||||
- alfresco
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 3001:80
|
||||
# volumes:
|
||||
# - ./app.config.json:/usr/share/nginx/html/app.config.json
|
||||
# - ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
|
||||
proxy:
|
||||
image: nginx
|
||||
depends_on:
|
||||
- content-app
|
||||
volumes:
|
||||
- ./docker-compose/nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 3000:80
|
||||
|
||||
networks:
|
||||
internal:
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
ALFRESCO_TAG=6.0.4-ea
|
||||
SHARE_TAG=6.0.a
|
||||
SOLR6_TAG=1.1.0
|
||||
POSTGRES_TAG=10.1
|
||||
ACA_TAG=development
|
||||
@@ -0,0 +1,15 @@
|
||||
# ACA with ACS Community 6.0ea
|
||||
|
||||
To run ACA together with the latest ACS community (6.0) use the following command:
|
||||
|
||||
```sh
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
The ACA is served on the port 3000.
|
||||
|
||||
If you want to teardown the environment, use the following command:
|
||||
|
||||
```sh
|
||||
docker-compose down
|
||||
```
|
||||
@@ -0,0 +1,94 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
alfresco:
|
||||
image: alfresco/alfresco-content-repository-community:${ALFRESCO_TAG}
|
||||
depends_on:
|
||||
- postgres
|
||||
environment:
|
||||
CATALINA_OPTS : "
|
||||
-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n
|
||||
"
|
||||
JAVA_OPTS : "
|
||||
-Ddb.driver=org.postgresql.Driver
|
||||
-Ddb.username=alfresco
|
||||
-Ddb.password=alfresco
|
||||
-Ddb.url=jdbc:postgresql://postgres:5432/alfresco
|
||||
-Dsolr.host=solr6
|
||||
-Dsolr.port=8983
|
||||
-Dsolr.secureComms=none
|
||||
-Dsolr.base.url=/solr
|
||||
-Dindex.subsystem.name=solr6
|
||||
"
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8080:8080 #Browser port
|
||||
- 8000:8000 #Debug port
|
||||
|
||||
share:
|
||||
image: alfresco/alfresco-share:${SHARE_TAG}
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
- REPO_HOST=alfresco
|
||||
- REPO_PORT=8080
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8081:8080
|
||||
|
||||
postgres:
|
||||
image: postgres:${POSTGRES_TAG}
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=alfresco
|
||||
- POSTGRES_USER=alfresco
|
||||
- POSTGRES_DB=alfresco
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 5432:5432
|
||||
|
||||
solr6:
|
||||
image: alfresco/alfresco-search-services:${SOLR6_TAG}
|
||||
depends_on:
|
||||
- alfresco
|
||||
environment:
|
||||
#Solr needs to know how to register itself with Alfresco
|
||||
- SOLR_ALFRESCO_HOST=alfresco
|
||||
- SOLR_ALFRESCO_PORT=8080
|
||||
#Alfresco needs to know how to call solr
|
||||
- SOLR_SOLR_HOST=solr6
|
||||
- SOLR_SOLR_PORT=8983
|
||||
#Create the default alfresco and archive cores
|
||||
- SOLR_CREATE_ALFRESCO_DEFAULTS=alfresco,archive
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 8983:8983 #Browser port
|
||||
|
||||
content-app:
|
||||
image: alfresco/alfresco-content-app:${ACA_TAG}
|
||||
depends_on:
|
||||
- alfresco
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 3001:80
|
||||
# volumes:
|
||||
# - ./app.config.json:/usr/share/nginx/html/app.config.json
|
||||
# - ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
|
||||
proxy:
|
||||
image: nginx
|
||||
depends_on:
|
||||
- content-app
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf
|
||||
networks:
|
||||
- internal
|
||||
ports:
|
||||
- 3000:80
|
||||
|
||||
networks:
|
||||
internal:
|
||||
@@ -0,0 +1,43 @@
|
||||
server {
|
||||
listen *:80;
|
||||
|
||||
set $allowOriginSite *;
|
||||
proxy_pass_request_headers on;
|
||||
proxy_pass_header Set-Cookie;
|
||||
|
||||
location / {
|
||||
proxy_pass http://content-app;
|
||||
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass_header Set-Cookie;
|
||||
}
|
||||
|
||||
location /alfresco/ {
|
||||
proxy_pass http://alfresco:8080;
|
||||
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass_header Set-Cookie;
|
||||
}
|
||||
|
||||
location /share/ {
|
||||
proxy_pass http://share:8080;
|
||||
|
||||
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
|
||||
proxy_redirect off;
|
||||
proxy_buffering off;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_pass_header Set-Cookie;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -17,7 +17,7 @@ with a simple and easy to use interface for working with files stored in the Alf
|
||||
|
||||
This application uses the latest releases from Alfresco:
|
||||
|
||||
- [Alfresco ADF version 2.2](https://community.alfresco.com/community/application-development-framework/pages/get-started)
|
||||
- [Alfresco ADF version 2.3](https://community.alfresco.com/community/application-development-framework/pages/get-started)
|
||||
- [Alfresco Content Services version 5.2.3](https://www.alfresco.com/platform/content-services-ecm)
|
||||
- [Alfresco Community Edition 201802 EA](https://www.alfresco.com/products/community/download)
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
The application runs at port 3000 by default, and should automatically open in the default browser once project compilation finishes.
|
||||
The application runs at port 4200 by default, and should automatically open in the default browser once project compilation finishes.
|
||||
|
||||
## Proxy settings
|
||||
|
||||
|
||||
@@ -21,11 +21,11 @@ The example below demonstrates the most common dynamic format for development en
|
||||
The configuration above assumes you are running ACS and Content App on the same server and port
|
||||
and allows deploying to different servers having the same unified configuration file.
|
||||
|
||||
For example, a proxy server at `localhost:3000` hosting the Content App as the root application,
|
||||
and `localhost:3000/alfresco` for the ACS repository.
|
||||
For example, a proxy server at `localhost:4200` hosting the Content App as the root application,
|
||||
and `localhost:4200/alfresco` for the ACS repository.
|
||||
|
||||
At runtime, the application is going to automatically substitute the "{hostname}" value with the original hostname.
|
||||
Optionally it can also use the value of the original port if present, for example, "3000" at local machines, or skip the value for port 80.
|
||||
Optionally it can also use the value of the original port if present, for example, "4200" at local machines, or skip the value for port 80.
|
||||
|
||||
### Static address
|
||||
|
||||
@@ -33,7 +33,7 @@ Alternatively, you can provide a static address for the ACS server if necessary:
|
||||
|
||||
```json
|
||||
{
|
||||
"ecmHost": "http://localhost:3000",
|
||||
"ecmHost": "http://localhost:4200",
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -128,6 +128,14 @@ actions are automatically hidden when the user does not have permission.
|
||||
once the delete action has completed the user is notified and can undo the action (which restores the items from the trash).
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Manage Versions</td>
|
||||
<td>
|
||||
Versions of files can be viewed, uploaded, restored, downloaded and deleted by using the version manager dialog;
|
||||
once each action has completed the list of versions is updated according to the change.
|
||||
</td>
|
||||
<td>Not applicable</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
+2
-2
@@ -77,7 +77,7 @@ To perform a cleanup operation, use the next command:
|
||||
docker-compose down --rmi all
|
||||
```
|
||||
|
||||
Navigate to "http://localhost:3000" to access the running application.
|
||||
Navigate to "http://localhost:4200" to access the running application.
|
||||
|
||||
<p class="warning">
|
||||
Please keep in mind that you should manually build the project every time you want to publish the image or run it locally with the container.
|
||||
@@ -101,7 +101,7 @@ npm run build:dev
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Navigate to "http://localhost:3000" to access the running application.
|
||||
Navigate to "http://localhost:4200" to access the running application.
|
||||
|
||||
To perform a cleanup operation, use the next command:
|
||||
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ The Header & Toolbar section of the viewer contains a number of features that re
|
||||
- Close 'X' will return the user to the folder that contains the file.
|
||||
- The name and file type icon is shown in the middle.
|
||||
- Next and previous buttons will be displayed either side of the file name so that users can navigate to other files in the folder without navigating away from the viewer.
|
||||
- Finally, on the right hand side an actions toolbar provides users with the ability to download, favorite, move, copy and delete.
|
||||
- Finally, on the right hand side an actions toolbar provides users with the ability to download, favorite, move, copy, delete, manage versions and view info panel.
|
||||
|
||||
#### Content (2)
|
||||
The File Viewer consists of four separate views that handle displaying the content based on four types of content, covering various [file/mime](https://alfresco.github.io/adf-component-catalog/components/ViewerComponent.html#supported-file-formats) types:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
+9
-1
@@ -24,7 +24,7 @@
|
||||
items: [
|
||||
{
|
||||
title: 'Introduction',
|
||||
path: 'features',
|
||||
path: 'features'
|
||||
},
|
||||
{
|
||||
title: 'Application Header',
|
||||
@@ -41,6 +41,14 @@
|
||||
{
|
||||
title: 'File Viewer',
|
||||
path: 'file-viewer'
|
||||
},
|
||||
{
|
||||
title: 'Info Drawer',
|
||||
path: 'info-drawer'
|
||||
},
|
||||
{
|
||||
title: 'Version Manager',
|
||||
path: 'version-manager'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
### Info Drawer
|
||||
|
||||
The Info Drawer displays node information in the right sidebar panel. It is created by using the [InfoDrawerComponent](https://alfresco.github.io/adf-component-catalog/components/InfoDrawerComponent.html). This info is available for both folder and file nodes.
|
||||
|
||||
Currently, there are 2 tabs available: Properties and Versions.
|
||||
|
||||
#### Properties tab
|
||||
|
||||
The Properties tab displays the node's metadata info by using the [ContentMetadataCardComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataCardComponent.html).
|
||||
|
||||

|
||||
|
||||
For more information, please check also the ADF's [ContentMetadataComponent](https://alfresco.github.io/adf-component-catalog/components/ContentMetadataComponent.html).
|
||||
|
||||
#### Versions tab
|
||||
|
||||
The Versions tab displays info about the node's versions and allows users to [manage versions](/version-manager), according to their permissions. Only the file nodes have version data available.
|
||||
|
||||

|
||||
|
||||
It uses the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html) from ADF framework.
|
||||
|
||||
Managing versions of a file can be possible also by accessing the 'Manage Versions' option from the 'More actions' menu. For more info on manage versions, please check the [version manager](/version-manager) page.
|
||||
@@ -0,0 +1,33 @@
|
||||
## Version Manager
|
||||
|
||||
The versions of a file can be viewed & managed by using the [VersionManagerComponent](https://alfresco.github.io/adf-component-catalog/components/VersionManagerComponent.html).
|
||||
|
||||
There are 2 ways users can access the Version Manager:
|
||||
|
||||
1. From the 'Manage Versions' option of the 'More actions' menu (check [Actions and the Actions Toolbar](/doc-list?id=actions-and-the-actions-toolbar)):
|
||||

|
||||

|
||||
|
||||
2. From the [Info Drawer](/info-drawer) (the Details right panel):
|
||||

|
||||
|
||||
### Upload new version
|
||||
|
||||
A new version for the selected file can be added by using this button. There is a restriction currently to only upload files of the same extension as the old version. The new version file will be automatically renamed to have the same name as the old version has. Please also check the [UploadVersionButtonComponent](https://alfresco.github.io/adf-component-catalog/components/UploadVersionButtonComponent.html).
|
||||
|
||||
### Actions Menu
|
||||
|
||||
Each item in the version list has a couple of actions available: Restore, Download and Delete. These are displayed if user has permission to do that specific action. The 'Download' and 'Delete' can be also disabled from the app.config.
|
||||
|
||||
In the app.config.json file, these are the current settings for the ACA version manager:
|
||||
```
|
||||
"adf-version-manager": {
|
||||
"allowComments": true,
|
||||
"allowDownload": true,
|
||||
"allowDelete": true
|
||||
},
|
||||
...
|
||||
```
|
||||
Set the allowComments to false if the version comments should not be displayed on the version list.
|
||||
|
||||
Clicking to delete a version of a file triggers a confirmation dialog. Please see the [ConfirmDialogComponent](https://alfresco.github.io/adf-component-catalog/components/ConfirmDialogComponent.html) for more info.
|
||||
Generated
+975
-3350
File diff suppressed because it is too large
Load Diff
+9
-6
@@ -5,19 +5,22 @@
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "npm run server-versions && ng serve --open",
|
||||
"build": "npm run server-versions && ng build",
|
||||
"start:prod": "npm run server-versions && ng serve --prod --open",
|
||||
"start:docker": "docker-compose up --build",
|
||||
"build": "npm run server-versions && ng build --prod",
|
||||
"build:prod": "npm run server-versions && ng build --prod",
|
||||
"build:dev": "npm run server-versions && ng build && node postbuild-dev.js",
|
||||
"build:dev": "npm run server-versions && ng build",
|
||||
"build:tomcat": "npm run server-versions && ng build --base-href ./",
|
||||
"test": "ng test --code-coverage",
|
||||
"test:ci": "ng test --code-coverage --single-run --no-progress && cat ./coverage/lcov.info | ./node_modules/.bin/codacy-coverage && rm -rf ./coverage",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e",
|
||||
"server-versions": "rimraf ./src/versions.json && npm list --depth=0 --json=true --prod=true > ./src/versions.json || exit 0"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@alfresco/adf-content-services": "2.2.0",
|
||||
"@alfresco/adf-core": "2.2.0",
|
||||
"@alfresco/adf-content-services": "2.3.0",
|
||||
"@alfresco/adf-core": "2.3.0",
|
||||
"@angular/animations": "5.1.1",
|
||||
"@angular/cdk": "5.0.1",
|
||||
"@angular/common": "5.1.1",
|
||||
@@ -34,7 +37,7 @@
|
||||
"@mat-datetimepicker/core": "1.0.1",
|
||||
"@mat-datetimepicker/moment": "1.0.1",
|
||||
"@ngx-translate/core": "9.1.1",
|
||||
"alfresco-js-api": "2.2.0",
|
||||
"alfresco-js-api": "2.3.0",
|
||||
"core-js": "2.5.3",
|
||||
"hammerjs": "2.0.8",
|
||||
"moment-es6": "1.0.0",
|
||||
@@ -44,7 +47,7 @@
|
||||
"zone.js": "0.8.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.6.6",
|
||||
"@angular/cli": "1.7.3",
|
||||
"@angular/compiler-cli": "5.1.1",
|
||||
"@angular/language-service": "5.1.1",
|
||||
"@types/jasmine": "^2.5.53",
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
var fs = require('fs');
|
||||
var config = require('./dist/app.config.json');
|
||||
|
||||
config.ecmHost = 'http://localhost:8080';
|
||||
|
||||
fs.writeFileSync(
|
||||
'./dist/app.config.json',
|
||||
JSON.stringify(config, null, 4)
|
||||
);
|
||||
+1
-1
@@ -28,7 +28,7 @@ exports.config = {
|
||||
|
||||
directConnect: true,
|
||||
|
||||
baseUrl: 'http://localhost:3000',
|
||||
baseUrl: 'http://localhost:4200',
|
||||
|
||||
framework: 'jasmine2',
|
||||
jasmineNodeOpts: {
|
||||
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
|
||||
show_help() {
|
||||
echo "Usage: docker_publish.sh"
|
||||
echo ""
|
||||
echo "--access_key rancher access key"
|
||||
echo "--secret_key rancher secret key"
|
||||
echo "--url rancher_url"
|
||||
echo "--environment_name service name to replace in rancher"
|
||||
echo "--image image to gater and load in the service, example: docker:alfresco/demo-shell:latest"
|
||||
}
|
||||
|
||||
access_key(){
|
||||
ACCESSKEY=$1
|
||||
}
|
||||
|
||||
secret_key(){
|
||||
SECRETKEY=$1
|
||||
}
|
||||
|
||||
url(){
|
||||
RANCHERURL=$1
|
||||
}
|
||||
|
||||
environment_name(){
|
||||
ENVIRONMENTNAME=$1
|
||||
}
|
||||
|
||||
image_name(){
|
||||
IMAGE=$1
|
||||
}
|
||||
|
||||
while [[ $1 == -* ]]; do
|
||||
case "$1" in
|
||||
-h|--help|-\?) show_help; exit 0;;
|
||||
--access_key) access_key $2; shift 2;;
|
||||
--secret_key) secret_key $2; shift 2;;
|
||||
--url) url $2; shift 2;;
|
||||
--environment_name) environment_name $2; shift 2;;
|
||||
--image) image_name $2; shift 2;;
|
||||
-*) echo "invalid option: $1" 1>&2; show_help; exit 1;;
|
||||
esac
|
||||
done
|
||||
|
||||
docker pull etlweather/gaucho:alpine
|
||||
|
||||
docker=$(which docker)
|
||||
|
||||
echo "getting the id"
|
||||
|
||||
ENVIRONMENTID=$($docker run --rm -e CATTLE_ACCESS_KEY=$ACCESSKEY \
|
||||
-e CATTLE_SECRET_KEY=$SECRETKEY \
|
||||
-e CATTLE_URL=$RANCHERURL \
|
||||
etlweather/gaucho:alpine id_of $ENVIRONMENTNAME)
|
||||
|
||||
echo "id retrieved! is ${environment_id}"
|
||||
|
||||
$docker run --rm -e CATTLE_ACCESS_KEY=$ACCESSKEY \
|
||||
-e CATTLE_SECRET_KEY=$SECRETKEY \
|
||||
-e CATTLE_URL=$RANCHERURL \
|
||||
etlweather/gaucho:alpine upgrade $ENVIRONMENTID --imageUuid $IMAGE --auto_complete true --timeout 600
|
||||
Executable
+134
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
eval JS_API=true
|
||||
eval GNU=false
|
||||
eval EXEC_COMPONENT=true
|
||||
eval DIFFERENT_JS_API=false
|
||||
eval AUTO=false
|
||||
|
||||
eval libs=( "core"
|
||||
"content-services"
|
||||
#"process-services"
|
||||
#"insights"
|
||||
)
|
||||
|
||||
cd ${DIR}/..
|
||||
|
||||
prefix="@alfresco/adf-"
|
||||
|
||||
show_help() {
|
||||
echo "Usage: update-version.sh"
|
||||
echo ""
|
||||
echo "-sj or -sjsapi don't update js-api version"
|
||||
echo "-vj or -versionjsapi to use a different version of js-api"
|
||||
echo "-v or -version version to update"
|
||||
echo "-alpha update last alpha version of js-api and lib automatically"
|
||||
echo "-beta update beta alpha version of js-api and lib automatically"
|
||||
echo "-gnu for gnu"
|
||||
}
|
||||
|
||||
skip_js() {
|
||||
echo "====== Skip JS-API change version $1 ====="
|
||||
JS_API=false
|
||||
}
|
||||
|
||||
last_alpha_mode() {
|
||||
echo "====== Auto find last ALPHA version ====="
|
||||
VERSION=$(npm view @alfresco/adf-core@alpha version)
|
||||
|
||||
echo "====== version lib ${VERSION} ====="
|
||||
|
||||
DIFFERENT_JS_API=true
|
||||
VERSION_JS_API=$(npm view alfresco-js-api@alpha version)
|
||||
|
||||
echo "====== version js-api ${DIFFERENT_JS_API} ====="
|
||||
}
|
||||
|
||||
last_beta_mode() {
|
||||
echo "====== Auto find last BETA version ====="
|
||||
VERSION=$(npm view @alfresco/adf-core@beta version)
|
||||
|
||||
echo "====== version lib ${VERSION} ====="
|
||||
|
||||
DIFFERENT_JS_API=true
|
||||
VERSION_JS_API=$(npm view alfresco-js-api@beta version)
|
||||
|
||||
echo "====== version js-api ${DIFFERENT_JS_API} ====="
|
||||
}
|
||||
|
||||
gnu_mode() {
|
||||
echo "====== GNU MODE ====="
|
||||
GNU=true
|
||||
}
|
||||
|
||||
version_change() {
|
||||
echo "====== New version $1 ====="
|
||||
VERSION=$1
|
||||
}
|
||||
|
||||
version_js_change() {
|
||||
echo "====== Alfresco JS-API version $1 ====="
|
||||
VERSION_JS_API=$1
|
||||
DIFFERENT_JS_API=true
|
||||
}
|
||||
|
||||
update_component_dependency_version(){
|
||||
for (( j=0; j<${libslength}; j++ ));
|
||||
do
|
||||
echo "====== UPDATE ${prefix}${libs[$j]} to ${VERSION}======"
|
||||
EXACT_VERSION="${prefix}${libs[$j]}@${VERSION}"
|
||||
npm install -E ${EXACT_VERSION}
|
||||
done
|
||||
}
|
||||
|
||||
update_component_js_version(){
|
||||
echo "====== UPDATE alfresco-js-api to ${1} ======"
|
||||
PACKAGETOCHANGE="alfresco-js-api"
|
||||
EXACT_VERSION="${PACKAGETOCHANGE}@${1}"
|
||||
npm install -E ${EXACT_VERSION}
|
||||
}
|
||||
|
||||
while [[ $1 == -* ]]; do
|
||||
case "$1" in
|
||||
-h|--help|-\?) show_help; exit 0;;
|
||||
-v|version) version_change $2; shift 2;;
|
||||
-sj|sjsapi) skip_js; shift;;
|
||||
-vj|versionjsapi) version_js_change $2; shift 2;;
|
||||
-gnu) gnu_mode; shift;;
|
||||
-alpha) last_alpha_mode; shift;;
|
||||
-beta) last_beta_mode; shift;;
|
||||
-*) shift;;
|
||||
esac
|
||||
done
|
||||
|
||||
if $GNU; then
|
||||
sedi='-i'
|
||||
else
|
||||
sedi=('-i' '')
|
||||
fi
|
||||
|
||||
if [[ "${VERSION}" == "" ]]
|
||||
then
|
||||
echo "Version number required"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
projectslength=${#projects[@]}
|
||||
libslength=${#libs[@]}
|
||||
|
||||
if $EXEC_COMPONENT == true; then
|
||||
echo "====== UPDATE ======"
|
||||
|
||||
update_component_dependency_version
|
||||
|
||||
if $JS_API == true; then
|
||||
|
||||
if $DIFFERENT_JS_API == true; then
|
||||
update_component_js_version ${VERSION_JS_API}
|
||||
else
|
||||
update_component_js_version ${VERSION}
|
||||
fi
|
||||
|
||||
fi
|
||||
fi
|
||||
+148
-2
@@ -2,11 +2,12 @@
|
||||
"ecmHost": "http://{hostname}{:port}",
|
||||
"application": {
|
||||
"name": "Alfresco Example Content Application",
|
||||
"logo": "/assets/images/alfresco-logo-white.svg"
|
||||
"logo": "assets/images/alfresco-logo-white.svg"
|
||||
},
|
||||
"headerColor": "#2196F3",
|
||||
"languagePicker": false,
|
||||
"pagination": {
|
||||
"size": 25,
|
||||
"supportedPageSizes": [
|
||||
25,
|
||||
50,
|
||||
@@ -21,6 +22,11 @@
|
||||
".git"
|
||||
]
|
||||
},
|
||||
"adf-version-manager": {
|
||||
"allowComments": true,
|
||||
"allowDownload": true,
|
||||
"allowDelete": true
|
||||
},
|
||||
"navigation": {
|
||||
"main": [
|
||||
{
|
||||
@@ -126,5 +132,145 @@
|
||||
"key": "zh-CN",
|
||||
"label": "Simplified Chinese"
|
||||
}
|
||||
]
|
||||
],
|
||||
"content-metadata": {
|
||||
"presets": {
|
||||
"custom": [
|
||||
{
|
||||
"title": "APP.CONTENT_METADATA.EXIF_GROUP_TITLE",
|
||||
"items": [
|
||||
{
|
||||
"aspect": "exif:exif",
|
||||
"properties": [
|
||||
"exif:pixelXDimension",
|
||||
"exif:pixelYDimension",
|
||||
"exif:dateTimeOriginal",
|
||||
"exif:exposureTime",
|
||||
"exif:fNumber",
|
||||
"exif:flash",
|
||||
"exif:focalLength",
|
||||
"exif:isoSpeedRatings",
|
||||
"exif:orientation",
|
||||
"exif:manufacturer",
|
||||
"exif:model",
|
||||
"exif:software"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"limits": {
|
||||
"permissionEvaluationTime": null,
|
||||
"permissionEvaluationCount": null
|
||||
},
|
||||
"filterQueries": [
|
||||
{ "query": "TYPE:'cm:folder' OR TYPE:'cm:content'" },
|
||||
{ "query": "NOT cm:creator:System" }
|
||||
],
|
||||
"facetFields": {
|
||||
"facets": [
|
||||
{ "field": "content.mimetype", "mincount": 1, "label": "Type" },
|
||||
{ "field": "content.size", "mincount": 1, "label": "Size" },
|
||||
{ "field": "creator", "mincount": 1, "label": "Creator" },
|
||||
{ "field": "modifier", "mincount": 1, "label": "Modifier" }
|
||||
]
|
||||
},
|
||||
"facetQueries": [
|
||||
{ "query": "created:2018", "label": "Created This Year" },
|
||||
{ "query": "content.mimetype", "label": "Type" },
|
||||
{ "query": "content.size:[0 TO 10240]", "label": "Size: xtra small"},
|
||||
{ "query": "content.size:[10240 TO 102400]", "label": "Size: small"},
|
||||
{ "query": "content.size:[102400 TO 1048576]", "label": "Size: medium" },
|
||||
{ "query": "content.size:[1048576 TO 16777216]", "label": "Size: large" },
|
||||
{ "query": "content.size:[16777216 TO 134217728]", "label": "Size: xtra large" },
|
||||
{ "query": "content.size:[134217728 TO MAX]", "label": "Size: XX large" }
|
||||
],
|
||||
"query": {
|
||||
"categories": [
|
||||
{
|
||||
"id": "broken",
|
||||
"name": "Broken Facet",
|
||||
"enabled": false,
|
||||
"expanded": false,
|
||||
"component": {
|
||||
"selector": "adf-search-text",
|
||||
"settings": {
|
||||
"field": "fieldname"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "queryName",
|
||||
"name": "Name",
|
||||
"enabled": true,
|
||||
"expanded": true,
|
||||
"component": {
|
||||
"selector": "adf-search-text",
|
||||
"settings": {
|
||||
"pattern": "cm:name:'(.*?)'",
|
||||
"field": "cm:name",
|
||||
"placeholder": "Enter the name"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "queryFields",
|
||||
"name": "Fields",
|
||||
"enabled": true,
|
||||
"expanded": false,
|
||||
"component": {
|
||||
"selector": "adf-search-fields",
|
||||
"settings": {
|
||||
"field": null,
|
||||
"options": [
|
||||
{ "name": "Name", "value": "name", "fields": ["name"], "default": true },
|
||||
{ "name": "File Size", "value": "content.sizeInBytes", "fields": ["content"], "default": true },
|
||||
{ "name": "Modified On", "value": "modifiedAt", "fields": ["modifiedAt"], "default": true },
|
||||
{ "name": "Modified By", "value": "modifiedByUser.displayName", "fields": ["modifiedByUser"], "default": true }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "queryType",
|
||||
"name": "Type",
|
||||
"enabled": true,
|
||||
"expanded": false,
|
||||
"component": {
|
||||
"selector": "adf-search-radio",
|
||||
"settings": {
|
||||
"field": null,
|
||||
"options": [
|
||||
{ "name": "None", "value": "", "default": true },
|
||||
{ "name": "All", "value": "TYPE:'cm:folder' OR TYPE:'cm:content'" },
|
||||
{ "name": "Folder", "value": "TYPE:'cm:folder'" },
|
||||
{ "name": "Document", "value": "TYPE:'cm:content'" }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "queryLocations",
|
||||
"name": "Locations",
|
||||
"enabled": true,
|
||||
"expanded": false,
|
||||
"component": {
|
||||
"selector": "adf-search-scope-locations",
|
||||
"settings": {
|
||||
"field": null,
|
||||
"options": [
|
||||
{ "name": "Default", "value": "nodes", "default": true },
|
||||
{ "name": "Nodes", "value": "nodes" },
|
||||
{ "name": "Deleted Nodes", "value": "deleted-nodes" },
|
||||
{ "name": "Versions", "value": "versions" }
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ export class AppComponent implements OnInit {
|
||||
config: AppConfigService) {
|
||||
// TODO: remove once ADF 2.3.0 is out (needs bug fixes)
|
||||
preferences.defaults.supportedPageSizes = config.get('pagination.supportedPageSizes');
|
||||
preferences.defaults.paginationSize = config.get('pagination.size');
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
+55
-12
@@ -26,11 +26,10 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TRANSLATION_PROVIDER } from '@alfresco/adf-core';
|
||||
|
||||
import { AdfModule } from './adf.module';
|
||||
import { CommonModule } from './common/common.module';
|
||||
import { MaterialModule } from './common/material.module';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { TRANSLATION_PROVIDER, CoreModule } from '@alfresco/adf-core';
|
||||
import { ContentModule } from '@alfresco/adf-content-services';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { APP_ROUTES } from './app.routes';
|
||||
@@ -47,22 +46,46 @@ import { TrashcanComponent } from './components/trashcan/trashcan.component';
|
||||
import { LayoutComponent } from './components/layout/layout.component';
|
||||
import { HeaderComponent } from './components/header/header.component';
|
||||
import { CurrentUserComponent } from './components/current-user/current-user.component';
|
||||
import { SearchComponent } from './components/search/search.component';
|
||||
import { SearchInputComponent } from './components/search-input/search-input.component';
|
||||
import { SidenavComponent } from './components/sidenav/sidenav.component';
|
||||
import { AboutComponent } from './components/about/about.component';
|
||||
import { LocationLinkComponent } from './components/location-link/location-link.component';
|
||||
import { EmptyFolderComponent } from './components/empty-folder/empty-folder.component';
|
||||
import { NodeCopyDirective } from './common/directives/node-copy.directive';
|
||||
import { NodeDeleteDirective } from './common/directives/node-delete.directive';
|
||||
import { NodeMoveDirective } from './common/directives/node-move.directive';
|
||||
import { NodeRestoreDirective } from './common/directives/node-restore.directive';
|
||||
import { NodePermanentDeleteDirective } from './common/directives/node-permanent-delete.directive';
|
||||
import { NodeUnshareDirective } from './common/directives/node-unshare.directive';
|
||||
import { NodeInfoDirective } from './common/directives/node-info.directive';
|
||||
import { NodeVersionsDirective } from './common/directives/node-versions.directive';
|
||||
import { AppConfigPipe } from './common/pipes/app-config.pipe';
|
||||
import { VersionManagerDialogAdapterComponent } from './components/versions-dialog/version-manager-dialog-adapter.component';
|
||||
import { BrowsingFilesService } from './common/services/browsing-files.service';
|
||||
import { ContentManagementService } from './common/services/content-management.service';
|
||||
import { NodeActionsService } from './common/services/node-actions.service';
|
||||
import { NodePermissionService } from './common/services/node-permission.service';
|
||||
import { MatMenuModule, MatIconModule, MatButtonModule, MatDialogModule, MatInputModule } from '@angular/material';
|
||||
import { SearchComponent } from './components/search/search.component';
|
||||
import { NodeDownloadDirective } from './common/directives/node-download.directive';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
RouterModule.forRoot(APP_ROUTES, {
|
||||
useHash: true,
|
||||
enableTracing: false // enable for debug only
|
||||
}),
|
||||
AdfModule,
|
||||
CommonModule,
|
||||
MaterialModule
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
MatInputModule,
|
||||
CoreModule,
|
||||
ContentModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent,
|
||||
@@ -71,7 +94,7 @@ import { EmptyFolderComponent } from './components/empty-folder/empty-folder.com
|
||||
LayoutComponent,
|
||||
HeaderComponent,
|
||||
CurrentUserComponent,
|
||||
SearchComponent,
|
||||
SearchInputComponent,
|
||||
SidenavComponent,
|
||||
FilesComponent,
|
||||
FavoritesComponent,
|
||||
@@ -82,7 +105,20 @@ import { EmptyFolderComponent } from './components/empty-folder/empty-folder.com
|
||||
PreviewComponent,
|
||||
AboutComponent,
|
||||
LocationLinkComponent,
|
||||
EmptyFolderComponent
|
||||
EmptyFolderComponent,
|
||||
NodeCopyDirective,
|
||||
NodeDeleteDirective,
|
||||
NodeMoveDirective,
|
||||
NodeRestoreDirective,
|
||||
NodePermanentDeleteDirective,
|
||||
NodeUnshareDirective,
|
||||
NodeInfoDirective,
|
||||
NodeVersionsDirective,
|
||||
AppConfigPipe,
|
||||
VersionManagerDialogAdapterComponent,
|
||||
SearchComponent,
|
||||
// Workarounds for ADF 2.3.0
|
||||
NodeDownloadDirective
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
@@ -92,7 +128,14 @@ import { EmptyFolderComponent } from './components/empty-folder/empty-folder.com
|
||||
name: 'app',
|
||||
source: 'assets'
|
||||
}
|
||||
}
|
||||
},
|
||||
BrowsingFilesService,
|
||||
ContentManagementService,
|
||||
NodeActionsService,
|
||||
NodePermissionService
|
||||
],
|
||||
entryComponents: [
|
||||
VersionManagerDialogAdapterComponent
|
||||
],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
|
||||
@@ -39,6 +39,7 @@ import { AboutComponent } from './components/about/about.component';
|
||||
import { LoginComponent } from './components/login/login.component';
|
||||
import { PreviewComponent } from './components/preview/preview.component';
|
||||
import { GenericErrorComponent } from './components/generic-error/generic-error.component';
|
||||
import { SearchComponent } from './components/search/search.component';
|
||||
|
||||
export const APP_ROUTES: Routes = [
|
||||
{
|
||||
@@ -215,6 +216,10 @@ export const APP_ROUTES: Routes = [
|
||||
i18nTitle: 'APP.BROWSE.ABOUT.TITLE'
|
||||
}
|
||||
},
|
||||
{
|
||||
path: 'search',
|
||||
component: SearchComponent
|
||||
},
|
||||
{
|
||||
path: '**',
|
||||
component: GenericErrorComponent
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { AdfModule } from '../adf.module';
|
||||
import { MaterialModule } from './material.module';
|
||||
|
||||
import { NodeCopyDirective } from './directives/node-copy.directive';
|
||||
import { NodeDeleteDirective } from './directives/node-delete.directive';
|
||||
import { NodeMoveDirective } from './directives/node-move.directive';
|
||||
import { NodeRestoreDirective } from './directives/node-restore.directive';
|
||||
import { NodePermanentDeleteDirective } from './directives/node-permanent-delete.directive';
|
||||
import { NodeUnshareDirective } from './directives/node-unshare.directive';
|
||||
|
||||
import { ContentManagementService } from './services/content-management.service';
|
||||
import { BrowsingFilesService } from './services/browsing-files.service';
|
||||
import { NodeActionsService } from './services/node-actions.service';
|
||||
|
||||
export function modules() {
|
||||
return [
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
MaterialModule,
|
||||
RouterModule,
|
||||
AdfModule
|
||||
];
|
||||
}
|
||||
|
||||
export function declarations() {
|
||||
return [
|
||||
NodeCopyDirective,
|
||||
NodeDeleteDirective,
|
||||
NodeMoveDirective,
|
||||
NodeRestoreDirective,
|
||||
NodePermanentDeleteDirective,
|
||||
NodeUnshareDirective
|
||||
];
|
||||
}
|
||||
|
||||
export function providers() {
|
||||
return [
|
||||
DatePipe,
|
||||
BrowsingFilesService,
|
||||
ContentManagementService,
|
||||
NodeActionsService
|
||||
];
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: modules(),
|
||||
declarations: declarations(),
|
||||
entryComponents: [],
|
||||
providers: providers(),
|
||||
exports: [
|
||||
...modules(),
|
||||
...declarations()
|
||||
]
|
||||
})
|
||||
export class CommonModule {}
|
||||
@@ -25,13 +25,15 @@
|
||||
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { TranslationService, NodesApiService, NotificationService } from '@alfresco/adf-core';
|
||||
import { TranslationService, NodesApiService, NotificationService, CoreModule } from '@alfresco/adf-core';
|
||||
import { Component, DebugElement } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { CommonModule } from '../common.module';
|
||||
import { NodeDeleteDirective } from './node-delete.directive';
|
||||
import { ContentManagementService } from '../services/content-management.service';
|
||||
import { MatSnackBarModule } from '@angular/material';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
template: '<div [app-delete-node]="selection"></div>'
|
||||
@@ -53,10 +55,18 @@ describe('NodeDeleteDirective', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CommonModule
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
CoreModule,
|
||||
MatSnackBarModule
|
||||
],
|
||||
declarations: [
|
||||
NodeDeleteDirective,
|
||||
TestComponent
|
||||
],
|
||||
providers: [
|
||||
ContentManagementService
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*!
|
||||
* @license
|
||||
* Copyright 2016 Alfresco Software, Ltd.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Directive, Input, HostListener } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { DownloadZipDialogComponent } from '@alfresco/adf-content-services';
|
||||
|
||||
/** @deprecated workaround for the ADF 2.3.0 regression. */
|
||||
@Directive({
|
||||
selector: '[appNodeDownload]'
|
||||
})
|
||||
export class NodeDownloadDirective {
|
||||
|
||||
/** Nodes to download. */
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input('appNodeDownload')
|
||||
nodes: MinimalNodeEntity[];
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
this.downloadNodes(this.nodes);
|
||||
}
|
||||
|
||||
constructor(
|
||||
private apiService: AlfrescoApiService,
|
||||
private dialog: MatDialog) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads multiple selected nodes.
|
||||
* Packs result into a .ZIP archive if there is more than one node selected.
|
||||
* @param selection Multiple selected nodes to download
|
||||
*/
|
||||
downloadNodes(selection: Array<MinimalNodeEntity>) {
|
||||
if (!selection || selection.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection.length === 1) {
|
||||
this.downloadNode(selection[0]);
|
||||
} else {
|
||||
this.downloadZip(selection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a single node.
|
||||
* Packs result into a .ZIP archive is the node is a Folder.
|
||||
* @param node Node to download
|
||||
*/
|
||||
downloadNode(node: MinimalNodeEntity) {
|
||||
if (node && node.entry) {
|
||||
const entry = node.entry;
|
||||
|
||||
if (entry.isFile) {
|
||||
this.downloadFile(node);
|
||||
}
|
||||
|
||||
if (entry.isFolder) {
|
||||
this.downloadZip([node]);
|
||||
}
|
||||
|
||||
// Check if there's nodeId for Shared Files
|
||||
if (!entry.isFile && !entry.isFolder && (<any> entry).nodeId) {
|
||||
this.downloadFile(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private downloadFile(node: MinimalNodeEntity) {
|
||||
if (node && node.entry) {
|
||||
const contentApi = this.apiService.getInstance().content;
|
||||
const id = (<any> node.entry).nodeId || node.entry.id;
|
||||
|
||||
const url = contentApi.getContentUrl(id, true);
|
||||
const fileName = node.entry.name;
|
||||
|
||||
this.download(url, fileName);
|
||||
}
|
||||
}
|
||||
|
||||
private downloadZip(selection: Array<MinimalNodeEntity>) {
|
||||
if (selection && selection.length > 0) {
|
||||
// nodeId for Shared node
|
||||
const nodeIds = selection.map((node: any) => (node.entry.nodeId || node.entry.id));
|
||||
|
||||
this.dialog.open(DownloadZipDialogComponent, {
|
||||
width: '600px',
|
||||
disableClose: true,
|
||||
data: {
|
||||
nodeIds
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private download(url: string, fileName: string) {
|
||||
if (url && fileName) {
|
||||
const link = document.createElement('a');
|
||||
|
||||
link.style.display = 'none';
|
||||
link.download = fileName;
|
||||
link.href = url;
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { ComponentFixture, TestBed, async, fakeAsync, tick } from '@angular/core/testing';
|
||||
import { AlfrescoApiService, CoreModule } from '@alfresco/adf-core';
|
||||
import { NodeInfoDirective } from './node-info.directive';
|
||||
|
||||
@Component({
|
||||
template: '<div [app-node-info]="selection"></div>'
|
||||
})
|
||||
class TestComponent {
|
||||
selection;
|
||||
}
|
||||
|
||||
describe('NodeInfoDirective', () => {
|
||||
let fixture: ComponentFixture<TestComponent>;
|
||||
let component: TestComponent;
|
||||
let apiService: AlfrescoApiService;
|
||||
let nodeService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule
|
||||
],
|
||||
declarations: [
|
||||
TestComponent,
|
||||
NodeInfoDirective
|
||||
]
|
||||
});
|
||||
|
||||
fixture = TestBed.createComponent(TestComponent);
|
||||
component = fixture.componentInstance;
|
||||
apiService = TestBed.get(AlfrescoApiService);
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
nodeService = apiService.getInstance().nodes;
|
||||
|
||||
spyOn(nodeService, 'getNodeInfo').and.returnValue(Promise.resolve({
|
||||
entry: { name: 'borg' }
|
||||
}));
|
||||
});
|
||||
|
||||
it('should not get node info onInit when selection is empty', () => {
|
||||
component.selection = [];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(nodeService.getNodeInfo).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get node info onInit when selection is not empty', () => {
|
||||
component.selection = [{ entry: { id: 'id' } }];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(nodeService.getNodeInfo).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not get node info on event when selection is empty', () => {
|
||||
component.selection = [];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
document.dispatchEvent(new CustomEvent('click'));
|
||||
|
||||
expect(nodeService.getNodeInfo).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get node info on event from selection', () => {
|
||||
component.selection = [{ entry: { id: 'id' } }];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
document.dispatchEvent(new CustomEvent('click'));
|
||||
|
||||
expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id', { include: [ 'allowableOperations' ] });
|
||||
});
|
||||
|
||||
|
||||
it('should get node info of last entry when selecting multiple nodes', fakeAsync(() => {
|
||||
component.selection = [
|
||||
{ entry: { id: 'id1', isFile: true } },
|
||||
{ entry: { id: 'id2', isFile: true } },
|
||||
{ entry: { id: 'id3', isFile: true } }
|
||||
];
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
document.dispatchEvent(new CustomEvent('click'));
|
||||
|
||||
fixture.detectChanges();
|
||||
tick();
|
||||
|
||||
expect(nodeService.getNodeInfo).toHaveBeenCalledWith('id3', { include: [ 'allowableOperations' ] });
|
||||
}));
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, HostListener, Input, Output, EventEmitter, OnInit } from '@angular/core';
|
||||
import { AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { MinimalNodeEntity, MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
|
||||
@Directive({
|
||||
selector: '[app-node-info]',
|
||||
exportAs: 'nodeInfo'
|
||||
})
|
||||
|
||||
export class NodeInfoDirective implements OnInit {
|
||||
@Input('app-node-info') selection: MinimalNodeEntity[];
|
||||
@Output() changed: EventEmitter<null|MinimalNodeEntryEntity> = new EventEmitter<null|MinimalNodeEntryEntity>();
|
||||
@Output() error: EventEmitter<null> = new EventEmitter<null>();
|
||||
|
||||
node: MinimalNodeEntryEntity;
|
||||
loading: boolean = null;
|
||||
|
||||
@HostListener('document:node-click', ['$event'])
|
||||
onClick(event) {
|
||||
this.getNodeInfo();
|
||||
}
|
||||
|
||||
constructor(private apiService: AlfrescoApiService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.getNodeInfo();
|
||||
}
|
||||
|
||||
getNodeInfo() {
|
||||
if (!this.selection.length) {
|
||||
this.node = null;
|
||||
this.loading = false;
|
||||
this.changed.emit(null);
|
||||
return;
|
||||
}
|
||||
|
||||
const node = this.selection[this.selection.length - 1];
|
||||
|
||||
if (node) {
|
||||
this.loading = true;
|
||||
|
||||
this.apiService.getInstance().nodes
|
||||
.getNodeInfo((<any>node.entry).nodeId || node.entry.id, {
|
||||
include: ['allowableOperations']
|
||||
})
|
||||
.then((data: MinimalNodeEntryEntity) => {
|
||||
this.node = data;
|
||||
this.changed.emit(data);
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(() => {
|
||||
this.error.emit();
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,12 +27,13 @@ import { Component, DebugElement } from '@angular/core';
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { TranslationService, NodesApiService, NotificationService, CoreModule } from '@alfresco/adf-core';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import { TranslationService, NodesApiService, NotificationService } from '@alfresco/adf-core';
|
||||
|
||||
import { CommonModule } from '../common.module';
|
||||
import { NodeActionsService } from '../services/node-actions.service';
|
||||
import { NodeMoveDirective } from './node-move.directive';
|
||||
import { ContentManagementService } from '../services/content-management.service';
|
||||
|
||||
@Component({
|
||||
template: '<div [app-move-node]="selection"></div>'
|
||||
@@ -53,10 +54,17 @@ describe('NodeMoveDirective', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CommonModule
|
||||
BrowserAnimationsModule,
|
||||
CoreModule
|
||||
],
|
||||
declarations: [
|
||||
NodeMoveDirective,
|
||||
TestComponent
|
||||
],
|
||||
providers: [
|
||||
DocumentListService,
|
||||
ContentManagementService,
|
||||
NodeActionsService
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
@@ -27,10 +27,10 @@ import { Component, DebugElement } from '@angular/core';
|
||||
import { TestBed, ComponentFixture, async, fakeAsync, tick } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { AlfrescoApiService, TranslationService, NotificationService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, TranslationService, NotificationService, CoreModule } from '@alfresco/adf-core';
|
||||
|
||||
import { CommonModule } from '../common.module';
|
||||
import { NodePermanentDeleteDirective } from './node-permanent-delete.directive';
|
||||
import { MatDialogModule, MatDialog } from '@angular/material';
|
||||
|
||||
@Component({
|
||||
template: `<div [app-permanent-delete-node]="selection"></div>`
|
||||
@@ -48,13 +48,16 @@ describe('NodePermanentDeleteDirective', () => {
|
||||
let notificationService: NotificationService;
|
||||
let nodesService;
|
||||
let directiveInstance;
|
||||
let dialog: MatDialog;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CommonModule
|
||||
CoreModule,
|
||||
MatDialogModule
|
||||
],
|
||||
declarations: [
|
||||
NodePermanentDeleteDirective,
|
||||
TestComponent
|
||||
]
|
||||
})
|
||||
@@ -65,16 +68,24 @@ describe('NodePermanentDeleteDirective', () => {
|
||||
element = fixture.debugElement.query(By.directive(NodePermanentDeleteDirective));
|
||||
directiveInstance = element.injector.get(NodePermanentDeleteDirective);
|
||||
|
||||
dialog = TestBed.get(MatDialog);
|
||||
alfrescoService = TestBed.get(AlfrescoApiService);
|
||||
nodesService = alfrescoService.getInstance().nodes;
|
||||
translation = TestBed.get(TranslationService);
|
||||
notificationService = TestBed.get(NotificationService);
|
||||
});
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
nodesService = alfrescoService.getInstance().nodes;
|
||||
|
||||
spyOn(translation, 'get').and.returnValue(Observable.of('message'));
|
||||
spyOn(notificationService, 'openSnackMessage').and.returnValue({});
|
||||
|
||||
spyOn(dialog, 'open').and.returnValue({
|
||||
afterClosed() {
|
||||
return Observable.of(true)
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('does not purge nodes if no selection', () => {
|
||||
|
||||
@@ -28,25 +28,44 @@ import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { TranslationService, AlfrescoApiService, NotificationService } from '@alfresco/adf-core';
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
import { MatDialog } from '@angular/material';
|
||||
import { ConfirmDialogComponent } from '@alfresco/adf-content-services';
|
||||
|
||||
@Directive({
|
||||
// tslint:disable-next-line:directive-selector
|
||||
selector: '[app-permanent-delete-node]'
|
||||
})
|
||||
export class NodePermanentDeleteDirective {
|
||||
|
||||
// tslint:disable-next-line:no-input-rename
|
||||
@Input('app-permanent-delete-node')
|
||||
selection: MinimalNodeEntity[];
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
this.purge();
|
||||
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
||||
data: {
|
||||
title: 'APP.DIALOGS.CONFIRM_PURGE.TITLE',
|
||||
message: 'APP.DIALOGS.CONFIRM_PURGE.MESSAGE',
|
||||
yesLabel: 'APP.DIALOGS.CONFIRM_PURGE.YES_LABEL',
|
||||
noLabel: 'APP.DIALOGS.CONFIRM_PURGE.NO_LABEL'
|
||||
},
|
||||
minWidth: '250px'
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(result => {
|
||||
if (result === true) {
|
||||
this.purge();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
constructor(
|
||||
private alfrescoApiService: AlfrescoApiService,
|
||||
private translation: TranslationService,
|
||||
private notification: NotificationService,
|
||||
private el: ElementRef
|
||||
private el: ElementRef,
|
||||
private dialog: MatDialog
|
||||
) {}
|
||||
|
||||
private purge() {
|
||||
|
||||
@@ -30,10 +30,10 @@ import { TestBed, ComponentFixture, async, fakeAsync, tick } from '@angular/core
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { CommonModule } from '../common.module';
|
||||
import { AlfrescoApiService, TranslationService, NotificationService } from '@alfresco/adf-core';
|
||||
import { AlfrescoApiService, TranslationService, NotificationService, CoreModule } from '@alfresco/adf-core';
|
||||
|
||||
import { NodeRestoreDirective } from './node-restore.directive';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
template: `<div [app-restore-node]="selection"></div>`
|
||||
@@ -57,10 +57,12 @@ describe('NodeRestoreDirective', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterTestingModule
|
||||
BrowserAnimationsModule,
|
||||
RouterTestingModule,
|
||||
CoreModule
|
||||
],
|
||||
declarations: [
|
||||
NodeRestoreDirective,
|
||||
TestComponent
|
||||
]
|
||||
})
|
||||
@@ -72,8 +74,6 @@ describe('NodeRestoreDirective', () => {
|
||||
directiveInstance = element.injector.get(NodeRestoreDirective);
|
||||
|
||||
alfrescoService = TestBed.get(AlfrescoApiService);
|
||||
nodesService = alfrescoService.getInstance().nodes;
|
||||
coreApi = alfrescoService.getInstance().core;
|
||||
translation = TestBed.get(TranslationService);
|
||||
notificationService = TestBed.get(NotificationService);
|
||||
router = TestBed.get(Router);
|
||||
@@ -81,6 +81,9 @@ describe('NodeRestoreDirective', () => {
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
nodesService = alfrescoService.getInstance().nodes;
|
||||
coreApi = alfrescoService.getInstance().core;
|
||||
|
||||
spyOn(translation, 'get').and.returnValue(Observable.of('message'));
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
||||
|
||||
import { TranslationService, NotificationService, AlfrescoApiService } from '@alfresco/adf-core';
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
|
||||
import { VersionManagerDialogAdapterComponent } from '../../components/versions-dialog/version-manager-dialog-adapter.component';
|
||||
import { MatDialog } from '@angular/material';
|
||||
|
||||
@Directive({
|
||||
selector: '[app-node-versions]'
|
||||
})
|
||||
export class NodeVersionsDirective {
|
||||
|
||||
@Input('app-node-versions')
|
||||
selection: MinimalNodeEntity[];
|
||||
|
||||
@Output()
|
||||
nodeVersionError: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
@HostListener('click')
|
||||
onClick() {
|
||||
this.onManageVersions();
|
||||
}
|
||||
|
||||
constructor(
|
||||
private apiService: AlfrescoApiService,
|
||||
private dialog: MatDialog,
|
||||
private notification: NotificationService,
|
||||
private translation: TranslationService
|
||||
) {}
|
||||
|
||||
onManageVersions() {
|
||||
const contentEntry = this.selection[0].entry;
|
||||
const nodeId = (<any>contentEntry).nodeId;
|
||||
|
||||
this.apiService.getInstance().nodes.getNodeInfo(nodeId || contentEntry.id, {
|
||||
include: ['allowableOperations']
|
||||
}).then(entry => this.openVersionManagerDialog(entry));
|
||||
|
||||
}
|
||||
|
||||
openVersionManagerDialog(contentEntry) {
|
||||
if (contentEntry.isFile) {
|
||||
this.dialog.open(
|
||||
VersionManagerDialogAdapterComponent,
|
||||
<any>{ data: { contentEntry }, panelClass: 'adf-version-manager-dialog', width: '630px' });
|
||||
} else {
|
||||
const translatedErrorMessage: any = this.translation.get('APP.MESSAGES.ERRORS.PERMISSION');
|
||||
this.notification.openSnackMessage(translatedErrorMessage.value, 4000);
|
||||
|
||||
this.nodeVersionError.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,21 +23,17 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
|
||||
// ADF modules
|
||||
import { CoreModule } from '@alfresco/adf-core';
|
||||
import { ContentModule } from '@alfresco/adf-content-services';
|
||||
|
||||
export function modules() {
|
||||
return [
|
||||
CoreModule,
|
||||
ContentModule
|
||||
];
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: modules(),
|
||||
exports: modules()
|
||||
@Pipe({
|
||||
name: 'appConfig',
|
||||
pure: true
|
||||
})
|
||||
export class AdfModule { }
|
||||
export class AppConfigPipe implements PipeTransform {
|
||||
constructor(private config: AppConfigService) {}
|
||||
|
||||
transform(value: string, fallback: any): any {
|
||||
return this.config.get(value, fallback);
|
||||
}
|
||||
}
|
||||
@@ -135,6 +135,7 @@ describe('NodeActionsService', () => {
|
||||
|
||||
service = TestBed.get(NodeActionsService);
|
||||
apiService = TestBed.get(AlfrescoApiService);
|
||||
apiService.reset();
|
||||
nodesApiService = TestBed.get(NodesApiService);
|
||||
nodesApi = apiService.getInstance().nodes;
|
||||
});
|
||||
|
||||
@@ -196,26 +196,12 @@ export class NodeActionsService {
|
||||
select: new Subject<MinimalNodeEntryEntity[]>()
|
||||
};
|
||||
|
||||
/*const matDialogRef =*/ this.dialog.open(ContentNodeSelectorComponent, <any>{
|
||||
this.dialog.open(ContentNodeSelectorComponent, <any>{
|
||||
data,
|
||||
panelClass: 'adf-content-node-selector-dialog',
|
||||
width: '630px'
|
||||
});
|
||||
|
||||
// todo: add back the fix for [ACA-1054]:
|
||||
/* const destinationPicker = matDialogRef.componentInstance;
|
||||
const initialSiteChanged = destinationPicker.siteChanged;
|
||||
|
||||
destinationPicker.siteChanged = (chosenSite) => {
|
||||
initialSiteChanged.call(destinationPicker, chosenSite);
|
||||
|
||||
if (chosenSite.guid === '-mysites-') {
|
||||
destinationPicker.documentList.data.setSorting(new DataSorting('title', 'asc'));
|
||||
} else {
|
||||
destinationPicker.documentList.data.setSorting(new DataSorting('name', 'asc'));
|
||||
}
|
||||
};*/
|
||||
|
||||
data.select.subscribe({
|
||||
complete: this.close.bind(this)
|
||||
});
|
||||
@@ -299,7 +285,7 @@ export class NodeActionsService {
|
||||
|
||||
// replace first item with 'File Libraries'
|
||||
elements[0].name = this.translation.instant('APP.BROWSE.LIBRARIES.TITLE');
|
||||
// elements[0].id = '-mysites-'; // commented this until navigation on custom sources is enabled on document-list
|
||||
elements[0].id = '-mysites-';
|
||||
|
||||
if (this.isSiteContainer(node)) {
|
||||
// rename 'documentLibrary' entry to the target site display name
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NodePermissionService } from './node-permission.service';
|
||||
|
||||
describe('NodePermissionService', () => {
|
||||
let permission: NodePermissionService;
|
||||
|
||||
beforeEach(() => {
|
||||
permission = new NodePermissionService();
|
||||
});
|
||||
|
||||
|
||||
it('should return false when source is null', () => {
|
||||
const source = null;
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
describe('Multiple source permission', () => {
|
||||
it('should return true when source has allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has allowableOperationsOnTarget permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['update'] } },
|
||||
{ entry: { allowableOperations: ['delete'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['update'] } },
|
||||
{ entry: { allowableOperationsOnTarget: ['delete'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when source has `OR` allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update' , 'delete'] } },
|
||||
{ entry: { allowableOperations: ['update', 'create'] } },
|
||||
{ entry: { allowableOperations: ['update', 'updatePermissions'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update', 'create'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has `AND` allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update' , 'delete', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update', 'other'], { operation: 'AND' })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source has no `AND` allowableOperations permission', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: ['update' , 'delete', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'create', 'other'] } },
|
||||
{ entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update', 'bogus'], { operation: 'AND' })).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations', () => {
|
||||
const source = [
|
||||
{ entry: { allowableOperations: [] } },
|
||||
{ entry: { allowableOperations: [] } },
|
||||
{ entry: { allowableOperations: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations property', () => {
|
||||
const source = [
|
||||
{ entry: { } },
|
||||
{ entry: { } },
|
||||
{ entry: { allowableOperations: ['update'] } }
|
||||
];
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('Single source permission', () => {
|
||||
it('should return true when source has allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update'] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has allowableOperationsOnTarget permission', () => {
|
||||
const source = { entry: { allowableOperationsOnTarget: ['update'] } };
|
||||
|
||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['delete'] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source does not have allowableOperationsOnTarget permission', () => {
|
||||
const source = { entry: { allowableOperationsOnTarget: ['delete'] } };
|
||||
|
||||
expect(permission.check(source, ['update'], { target: 'allowableOperationsOnTarget' })).toBe(false);
|
||||
});
|
||||
|
||||
it('should return true when source has `OR` allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update'] } };
|
||||
|
||||
expect(permission.check(source, ['update', 'create'])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return true when source has `AND` allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update', 'other'] } };
|
||||
|
||||
expect(permission.check(source, ['update', 'other'], { operation: 'AND' })).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false when source has no `AND` allowableOperations permission', () => {
|
||||
const source = { entry: { allowableOperations: ['update', 'updatePermissions', 'other'] } };
|
||||
|
||||
expect(permission.check(source, ['update', 'bogus'], { operation: 'AND' })).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations', () => {
|
||||
const source = { entry: { allowableOperations: [] } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false when source has no allowableOperations property', () => {
|
||||
const source = { entry: { } };
|
||||
|
||||
expect(permission.check(source, ['update'])).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,84 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class NodePermissionService {
|
||||
static DEFAULT_OPERATION = 'OR';
|
||||
|
||||
private defaultOptions = {
|
||||
operation: NodePermissionService.DEFAULT_OPERATION,
|
||||
target: null
|
||||
};
|
||||
|
||||
check(source: any, permissions: string[], options: any = {}): boolean {
|
||||
const opts = Object.assign({}, this.defaultOptions, options);
|
||||
|
||||
if (source) {
|
||||
if (Array.isArray(source) && source.length) {
|
||||
const arr = this.sanitize(source);
|
||||
|
||||
return !!arr.length && source.every(node => this.hasPermission(node, permissions, opts));
|
||||
}
|
||||
|
||||
return this.hasPermission(source, permissions, opts);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private hasPermission(node, permissions, options): boolean {
|
||||
const allowableOperations = this.getAllowableOperations(node, options.target);
|
||||
|
||||
if (allowableOperations.length) {
|
||||
if (options.operation === NodePermissionService.DEFAULT_OPERATION) {
|
||||
return permissions.some(permission => allowableOperations.includes(permission));
|
||||
} else {
|
||||
return permissions.every(permission => allowableOperations.includes(permission));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private getAllowableOperations(node, target): string[] {
|
||||
const entry = node.entry || node;
|
||||
|
||||
if (!target && entry.allowableOperations) {
|
||||
return entry.allowableOperations;
|
||||
}
|
||||
|
||||
if (target && entry[target]) {
|
||||
return entry[target];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
private sanitize(selection): any[] {
|
||||
return (selection || []).filter(item => item);
|
||||
}
|
||||
}
|
||||
@@ -1,46 +1,48 @@
|
||||
<div class="inner-layout inner-layout--scroll">
|
||||
<div class="inner-layout__content inner-layout__content--scroll">
|
||||
<article *ngIf="ecmVersion" class="padding">
|
||||
<header class="header padding-left">Alfresco Content Services</header>
|
||||
<p class="padding-left"> version: {{ ecmVersion.edition }} {{ ecmVersion.version.display }} </p>
|
||||
</article>
|
||||
<div class="inner-layout__content">
|
||||
<div class="inner-layout__panel content--scroll">
|
||||
<article *ngIf="ecmVersion" class="padding">
|
||||
<header class="header padding-left">Alfresco Content Services</header>
|
||||
<p class="padding-left"> version: {{ ecmVersion.edition }} {{ ecmVersion.version.display }} </p>
|
||||
</article>
|
||||
|
||||
<article class="padding-top-bottom">
|
||||
<header class="header padding-left-right">License</header>
|
||||
<adf-datatable [data]="license"></adf-datatable>
|
||||
</article>
|
||||
<article class="padding-top-bottom">
|
||||
<header class="header padding-left-right">License</header>
|
||||
<adf-datatable [data]="license"></adf-datatable>
|
||||
</article>
|
||||
|
||||
<article class="padding-top-bottom">
|
||||
<header class="header padding-left-right">Status</header>
|
||||
<adf-datatable [data]="status"></adf-datatable>
|
||||
</article>
|
||||
<article class="padding-top-bottom">
|
||||
<header class="header padding-left-right">Status</header>
|
||||
<adf-datatable [data]="status"></adf-datatable>
|
||||
</article>
|
||||
|
||||
<article class="padding-top-bottom">
|
||||
<header class="header padding-left-right">Modules</header>
|
||||
<adf-datatable [data]="modules"></adf-datatable>
|
||||
</article>
|
||||
<article class="padding-top-bottom">
|
||||
<header class="header padding-left-right">Modules</header>
|
||||
<adf-datatable [data]="modules"></adf-datatable>
|
||||
</article>
|
||||
|
||||
<article class="padding">
|
||||
<header class="header padding-left">Alfresco Content Application</header>
|
||||
<p class="padding-left"> version: 1.0 </p>
|
||||
</article>
|
||||
<article class="padding">
|
||||
<header class="header padding-left">Alfresco Content Application</header>
|
||||
<p class="padding-left"> version: {{ releaseVersion }} </p>
|
||||
</article>
|
||||
|
||||
<article *ngIf="githubUrlCommitAlpha" class="padding">
|
||||
<header class="header">Source code</header>
|
||||
<article *ngIf="githubUrlCommitAlpha" class="padding">
|
||||
<header class="header">Source code</header>
|
||||
|
||||
<small>You are running the project based on the following commit:</small>
|
||||
<small>You are running the project based on the following commit:</small>
|
||||
|
||||
<p>
|
||||
<a [href]="githubUrlCommitAlpha" target="blank">{{githubUrlCommitAlpha}}</a>
|
||||
</p>
|
||||
</article>
|
||||
<p>
|
||||
<a [href]="githubUrlCommitAlpha" target="blank">{{githubUrlCommitAlpha}}</a>
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article>
|
||||
<header class="header padding-left-right">Packages</header>
|
||||
<article>
|
||||
<header class="header padding-left-right">Packages</header>
|
||||
|
||||
<small class="padding-left-right">Current project is using the following ADF libraries:</small>
|
||||
<small class="padding-left-right">Current project is using the following ADF libraries:</small>
|
||||
|
||||
<adf-datatable [data]="data"></adf-datatable>
|
||||
</article>
|
||||
<adf-datatable [data]="data"></adf-datatable>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -40,7 +40,7 @@ export class AboutComponent implements OnInit {
|
||||
license: ObjectDataTableAdapter;
|
||||
modules: ObjectDataTableAdapter;
|
||||
githubUrlCommitAlpha = 'https://github.com/Alfresco/alfresco-content-app/commits';
|
||||
|
||||
releaseVersion = '';
|
||||
|
||||
constructor(
|
||||
private discovery: DiscoveryApiService,
|
||||
@@ -55,7 +55,7 @@ export class AboutComponent implements OnInit {
|
||||
{type: 'text', key: 'id', title: 'ID', sortable: true},
|
||||
{type: 'text', key: 'title', title: 'Title', sortable: true},
|
||||
{type: 'text', key: 'version', title: 'Description', sortable: true},
|
||||
{type: 'text', key: 'installDate', title: 'Install Date', sortable: true},
|
||||
{type: 'date', key: 'installDate', title: 'Install Date', sortable: true},
|
||||
{type: 'text', key: 'installState', title: 'Install State', sortable: true},
|
||||
{type: 'text', key: 'versionMin', title: 'Version Minor', sortable: true},
|
||||
{type: 'text', key: 'versionMax', title: 'Version Max', sortable: true}
|
||||
@@ -69,8 +69,8 @@ export class AboutComponent implements OnInit {
|
||||
]);
|
||||
|
||||
this.license = new ObjectDataTableAdapter([this.ecmVersion.license], [
|
||||
{type: 'text', key: 'issuedAt', title: 'Issued At', sortable: true},
|
||||
{type: 'text', key: 'expiresAt', title: 'Expires At', sortable: true},
|
||||
{type: 'date', key: 'issuedAt', title: 'Issued At', sortable: true},
|
||||
{type: 'date', key: 'expiresAt', title: 'Expires At', sortable: true},
|
||||
{type: 'text', key: 'remainingDays', title: 'Remaining Days', sortable: true},
|
||||
{type: 'text', key: 'holder', title: 'Holder', sortable: true},
|
||||
{type: 'text', key: 'mode', title: 'Type', sortable: true},
|
||||
@@ -79,20 +79,24 @@ export class AboutComponent implements OnInit {
|
||||
]);
|
||||
});
|
||||
|
||||
this.http.get('/versions.json').subscribe(response => {
|
||||
const regexp = new RegExp('^(@alfresco|alfresco-)');
|
||||
this.http.get('/versions.json')
|
||||
.map(response => response.json())
|
||||
.subscribe(response => {
|
||||
const regexp = new RegExp('^(@alfresco|alfresco-)');
|
||||
|
||||
const alfrescoPackagesTableRepresentation = Object.keys(response.json().dependencies)
|
||||
.filter((val) => regexp.test(val))
|
||||
.map((val) => ({
|
||||
name: val,
|
||||
version: response.json().dependencies[val].version
|
||||
}));
|
||||
const alfrescoPackagesTableRepresentation = Object.keys(response.dependencies)
|
||||
.filter((val) => regexp.test(val))
|
||||
.map((val) => ({
|
||||
name: val,
|
||||
version: response.dependencies[val].version
|
||||
}));
|
||||
|
||||
this.data = new ObjectDataTableAdapter(alfrescoPackagesTableRepresentation, [
|
||||
{type: 'text', key: 'name', title: 'Name', sortable: true},
|
||||
{type: 'text', key: 'version', title: 'Version', sortable: true}
|
||||
]);
|
||||
});
|
||||
this.data = new ObjectDataTableAdapter(alfrescoPackagesTableRepresentation, [
|
||||
{type: 'text', key: 'name', title: 'Name', sortable: true},
|
||||
{type: 'text', key: 'version', title: 'Version', sortable: true}
|
||||
]);
|
||||
|
||||
this.releaseVersion = response.version;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="canPreviewFile(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
(click)="onNodeDoubleClick(documentList.selection[0]?.entry)">
|
||||
@@ -15,6 +16,7 @@
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
[adfNodeDownload]="documentList.selection">
|
||||
@@ -23,13 +25,24 @@
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="showEditOption(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.EDIT' | translate }}"
|
||||
(error)="openSnackMessage($event)"
|
||||
[adf-edit-folder]="documentList.selection[0]?.entry">
|
||||
<mat-icon>create</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="documentList.selection.length"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
@@ -44,7 +57,10 @@
|
||||
#selection="adfFavorite"
|
||||
(toggle)="refresh()"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
<mat-icon [ngClass]="{ 'icon-highlight': selection.hasFavorites() }">
|
||||
<mat-icon [ngClass]="{
|
||||
'toolbar__option--active': selection.hasFavorites(),
|
||||
'toolbar__option--default': !selection.hasFavorites()
|
||||
}">
|
||||
{{ selection.hasFavorites() ? 'star' :'star_border' }}
|
||||
</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@@ -53,100 +69,148 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
[app-copy-node]="documentList.selection">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<mat-icon color="primary">content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[app-move-node]="documentList.selection">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<mat-icon color="primary">library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
[app-delete-node]="documentList.selection">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<mat-icon color="primary">delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="isFileSelected(documentList.selection)"
|
||||
[app-node-versions]="documentList.selection">
|
||||
<mat-icon color="primary">history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</adf-toolbar>
|
||||
</div>
|
||||
<div class="inner-layout__content">
|
||||
<div class="inner-layout__panel" [ngClass]="{'adf-document-list--loading': documentList.isEmpty()}">
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'adf-document-list--empty' : ''"
|
||||
currentFolderId="-favorites-"
|
||||
selectionMode="multiple"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
|
||||
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
|
||||
currentFolderId="-favorites-"
|
||||
selectionMode="multiple"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="star_rate"
|
||||
title="APP.BROWSE.FAVORITES.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.FAVORITES.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-columns>
|
||||
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="star_rate"
|
||||
title="APP.BROWSE.FAVORITES.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.FAVORITES.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
<data-columns>
|
||||
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
|
||||
type="fileSize">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="modifiedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
|
||||
</data-column>
|
||||
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
|
||||
<ng-container *ngIf="!documentList.isEmpty()">
|
||||
<adf-pagination
|
||||
[supportedPageSizes]="'pagination.supportedPageSizes' | appConfig"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[app-node-info]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(infoInstance.node, ['update'])"
|
||||
[displayEmpty]="permission.check(infoInstance.node, ['update'])"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="infoInstance.node?.isFile;else choose_document_template">
|
||||
<adf-version-manager [node]="infoInstance.node"></adf-version-manager>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
|
||||
type="fileSize">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="modifiedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
|
||||
</data-column>
|
||||
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,13 +37,16 @@ import {
|
||||
AuthenticationService, TimeAgoPipe, NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective, DataTableComponent
|
||||
} from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services';
|
||||
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { AppConfigPipe } from '../../common/pipes/app-config.pipe';
|
||||
|
||||
import { FavoritesComponent } from './favorites.component';
|
||||
|
||||
@@ -55,6 +58,7 @@ describe('Favorites Routed Component', () => {
|
||||
let alfrescoContentService: ContentService;
|
||||
let contentService: ContentManagementService;
|
||||
let preferenceService: UserPreferencesService;
|
||||
let notificationService: NotificationService;
|
||||
let router: Router;
|
||||
let page;
|
||||
let node;
|
||||
@@ -100,8 +104,10 @@ describe('Favorites Routed Component', () => {
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
FavoritesComponent
|
||||
FavoritesComponent,
|
||||
AppConfigPipe
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: {
|
||||
@@ -112,11 +118,13 @@ describe('Favorites Routed Component', () => {
|
||||
UserPreferencesService,
|
||||
AppConfigService, StorageService, CookieService,
|
||||
AlfrescoApiService,
|
||||
CustomResourcesService,
|
||||
LogService,
|
||||
NotificationService,
|
||||
ContentManagementService,
|
||||
ContentService,
|
||||
NodesApiService,
|
||||
NodePermissionService,
|
||||
DocumentListService,
|
||||
ThumbnailService
|
||||
],
|
||||
@@ -127,7 +135,9 @@ describe('Favorites Routed Component', () => {
|
||||
component = fixture.componentInstance;
|
||||
|
||||
nodesApi = TestBed.get(NodesApiService);
|
||||
notificationService = TestBed.get(NotificationService);
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
alfrescoApi.reset();
|
||||
alfrescoContentService = TestBed.get(ContentService);
|
||||
contentService = TestBed.get(ContentManagementService);
|
||||
preferenceService = TestBed.get(UserPreferencesService);
|
||||
@@ -319,4 +329,16 @@ describe('Favorites Routed Component', () => {
|
||||
expect(preferenceService.set).toHaveBeenCalledWith('prefix.sorting.direction', 'desc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('openSnackMessage', () => {
|
||||
it('should call notification service', () => {
|
||||
const message = 'notification message';
|
||||
|
||||
spyOn(notificationService, 'openSnackMessage');
|
||||
|
||||
component.openSnackMessage(message);
|
||||
|
||||
expect(notificationService.openSnackMessage).toHaveBeenCalledWith(message, 4000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -28,10 +28,11 @@ import { Router, ActivatedRoute } from '@angular/router';
|
||||
import { Subscription } from 'rxjs/Rx';
|
||||
|
||||
import { MinimalNodeEntryEntity, MinimalNodeEntity, PathElementEntity, PathInfo } from 'alfresco-js-api';
|
||||
import { ContentService, NodesApiService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { ContentService, NodesApiService, UserPreferencesService, NotificationService } from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { PageComponent } from '../page.component';
|
||||
|
||||
@Component({
|
||||
@@ -51,6 +52,8 @@ export class FavoritesComponent extends PageComponent implements OnInit, OnDestr
|
||||
private nodesApi: NodesApiService,
|
||||
private contentService: ContentService,
|
||||
private content: ContentManagementService,
|
||||
private notificationService: NotificationService,
|
||||
public permission: NodePermissionService,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences);
|
||||
|
||||
@@ -122,6 +125,13 @@ export class FavoritesComponent extends PageComponent implements OnInit, OnDestr
|
||||
this.preferences.set(`${this.prefix}.sorting.direction`, event.detail.direction || 'desc');
|
||||
}
|
||||
|
||||
openSnackMessage(event: any) {
|
||||
this.notificationService.openSnackMessage(
|
||||
event,
|
||||
4000
|
||||
);
|
||||
}
|
||||
|
||||
private get prefix() {
|
||||
return this.route.snapshot.data.preferencePrefix;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="canPreviewFile(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
@@ -16,6 +17,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
@@ -24,14 +26,25 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="canEditFolder(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.EDIT' | translate }}"
|
||||
(error)="openSnackMessage($event)"
|
||||
[adf-edit-folder]="documentList.selection[0]?.entry">
|
||||
<mat-icon>create</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="documentList.selection.length"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
@@ -46,7 +59,10 @@
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
<mat-icon [ngClass]="{ 'icon-highlight': selection.hasFavorites() }">
|
||||
<mat-icon [ngClass]="{
|
||||
'toolbar__option--active': selection.hasFavorites(),
|
||||
'toolbar__option--default': !selection.hasFavorites()
|
||||
}">
|
||||
{{ selection.hasFavorites() ? 'star' :'star_border' }}
|
||||
</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@@ -55,7 +71,7 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
[app-copy-node]="documentList.selection">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<mat-icon color="primary">content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
@@ -63,7 +79,7 @@
|
||||
mat-menu-item
|
||||
*ngIf="canMove(documentList.selection)"
|
||||
[app-move-node]="documentList.selection">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<mat-icon color="primary">library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
@@ -71,88 +87,135 @@
|
||||
mat-menu-item
|
||||
*ngIf="canDelete(documentList.selection)"
|
||||
[app-delete-node]="documentList.selection">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<mat-icon color="primary">delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canManageVersions(documentList.selection)"
|
||||
[app-node-versions]="documentList.selection">
|
||||
<mat-icon color="primary">history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</adf-toolbar>
|
||||
</div>
|
||||
|
||||
<div [attr.class]="isValidPath ? 'content--hide' : 'inner-layout__content'">
|
||||
<div [attr.class]="isValidPath ? 'inner-layout__content--hide' : 'inner-layout__content'">
|
||||
<app-generic-error></app-generic-error>
|
||||
</div>
|
||||
|
||||
<div [attr.class]="!isValidPath ? 'content--hide' : 'inner-layout__content'">
|
||||
<adf-upload-drag-area
|
||||
[parentId]="node?.id"
|
||||
[disabled]="!canCreateContent(node)">
|
||||
<div [attr.class]="!isValidPath ? 'inner-layout__content--hide' : 'inner-layout__content'">
|
||||
<div class="inner-layout__panel" [ngClass]="{'adf-document-list--loading': isLoading}">
|
||||
<adf-upload-drag-area
|
||||
[parentId]="node?.id"
|
||||
[disabled]="!permission.check(node, ['create'])">
|
||||
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
|
||||
[loading]="isLoading"
|
||||
[node]="paging"
|
||||
[sorting]="sorting"
|
||||
[allowDropFiles]="true"
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'adf-document-list--empty' : ''"
|
||||
[loading]="isLoading"
|
||||
[node]="paging"
|
||||
[sorting]="sorting"
|
||||
[allowDropFiles]="true"
|
||||
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
[navigate]="false"
|
||||
[selectionMode]="'multiple'"
|
||||
[imageResolver]="imageResolver"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
[navigate]="false"
|
||||
[selectionMode]="'multiple'"
|
||||
[imageResolver]="imageResolver"
|
||||
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event)"
|
||||
(node-select)="onNodeSelect($event, documentList)">
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event)"
|
||||
(node-select)="onNodeSelect($event, documentList)">
|
||||
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value }} bytes">{{ value | adfFileSize }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value }} bytes">{{ value | adfFileSize }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="modifiedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="modifiedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
|
||||
<ng-container *ngIf="!isEmpty">
|
||||
<adf-pagination
|
||||
[supportedPageSizes]="documentList.supportedPageSizes"
|
||||
[pagination]="pagination"
|
||||
(change)="load(true, $event)"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</ng-container>
|
||||
</adf-upload-drag-area>
|
||||
<ng-container *ngIf="!isEmpty">
|
||||
<adf-pagination
|
||||
[supportedPageSizes]="'pagination.supportedPageSizes' | appConfig"
|
||||
[pagination]="pagination"
|
||||
(change)="load(true, $event)"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</ng-container>
|
||||
</adf-upload-drag-area>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[app-node-info]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!canUpdate(documentList.selection)"
|
||||
[displayEmpty]="canUpdate(documentList.selection)"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="isFileSelected(documentList.selection);else choose_document_template">
|
||||
<adf-version-manager
|
||||
*ngIf="infoInstance.node"
|
||||
[node]="infoInstance.node">
|
||||
</adf-version-manager>
|
||||
</ng-container>
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,12 +39,15 @@ import {
|
||||
TimeAgoPipe, NodeNameTooltipPipe, FileSizePipe, NodeFavoriteDirective,
|
||||
DataTableComponent, UploadService
|
||||
} from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule, MatDialogModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { NodeActionsService } from '../../common/services/node-actions.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
import { AppConfigPipe } from '../../common/pipes/app-config.pipe';
|
||||
|
||||
import { FilesComponent } from './files.component';
|
||||
|
||||
@@ -61,6 +64,7 @@ describe('FilesComponent', () => {
|
||||
let browsingFilesService: BrowsingFilesService;
|
||||
let nodeActionsService: NodeActionsService;
|
||||
let preferenceService: UserPreferencesService;
|
||||
let notificationService: NotificationService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
@@ -79,8 +83,10 @@ describe('FilesComponent', () => {
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
FileSizePipe
|
||||
FileSizePipe,
|
||||
AppConfigPipe
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: {
|
||||
@@ -100,8 +106,10 @@ describe('FilesComponent', () => {
|
||||
DocumentListService,
|
||||
ThumbnailService,
|
||||
NodeActionsService,
|
||||
NodePermissionService,
|
||||
UploadService,
|
||||
BrowsingFilesService
|
||||
BrowsingFilesService,
|
||||
CustomResourcesService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
}).compileComponents()
|
||||
@@ -116,6 +124,7 @@ describe('FilesComponent', () => {
|
||||
router = TestBed.get(Router);
|
||||
alfrescoContentService = TestBed.get(ContentService);
|
||||
browsingFilesService = TestBed.get(BrowsingFilesService);
|
||||
notificationService = TestBed.get(NotificationService);
|
||||
nodeActionsService = TestBed.get(NodeActionsService);
|
||||
preferenceService = TestBed.get(UserPreferencesService);
|
||||
});
|
||||
@@ -324,31 +333,6 @@ describe('FilesComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Create permission', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(component, 'fetchNode').and.returnValue(Observable.of(node));
|
||||
spyOn(component, 'fetchNodes').and.returnValue(Observable.of(page));
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('returns false when node is not provided', () => {
|
||||
expect(component.canCreateContent(null)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when node does not have permission', () => {
|
||||
spyOn(alfrescoContentService, 'hasPermission').and.returnValue(false);
|
||||
|
||||
expect(component.canCreateContent(node)).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when node has permission', () => {
|
||||
spyOn(alfrescoContentService, 'hasPermission').and.returnValue(true);
|
||||
|
||||
expect(component.canCreateContent(node)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('onNodeDoubleClick()', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(component, 'fetchNode').and.returnValue(Observable.of(node));
|
||||
@@ -436,7 +420,7 @@ describe('FilesComponent', () => {
|
||||
component.load();
|
||||
|
||||
expect(component.paging).toBe(page);
|
||||
expect(component.pagination).toBe(page.list.pagination);
|
||||
expect(component.pagination).toEqual(page.list.pagination);
|
||||
});
|
||||
|
||||
it('raise error on fail', () => {
|
||||
@@ -551,4 +535,16 @@ describe('FilesComponent', () => {
|
||||
expect(preferenceService.set).toHaveBeenCalledWith('prefix.sorting.direction', 'desc');
|
||||
});
|
||||
});
|
||||
|
||||
describe('openSnackMessage', () => {
|
||||
it('should call notification service', () => {
|
||||
const message = 'notification message';
|
||||
|
||||
spyOn(notificationService, 'openSnackMessage');
|
||||
|
||||
component.openSnackMessage(message);
|
||||
|
||||
expect(notificationService.openSnackMessage).toHaveBeenCalledWith(message, 4000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -29,12 +29,13 @@ import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||
import { MinimalNodeEntity, MinimalNodeEntryEntity, PathElementEntity, NodePaging, PathElement } from 'alfresco-js-api';
|
||||
import {
|
||||
UploadService, FileUploadEvent, NodesApiService,
|
||||
ContentService, AlfrescoApiService, UserPreferencesService
|
||||
ContentService, AlfrescoApiService, UserPreferencesService, NotificationService
|
||||
} from '@alfresco/adf-core';
|
||||
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeActionsService } from '../../common/services/node-actions.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
import { PageComponent } from '../page.component';
|
||||
|
||||
@@ -43,7 +44,6 @@ import { PageComponent } from '../page.component';
|
||||
})
|
||||
export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
|
||||
private routeData: any = {};
|
||||
isValidPath = true;
|
||||
|
||||
private nodePath: PathElement[];
|
||||
@@ -61,6 +61,8 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
private browsingFilesService: BrowsingFilesService,
|
||||
private contentService: ContentService,
|
||||
private apiService: AlfrescoApiService,
|
||||
private notificationService: NotificationService,
|
||||
public permission: NodePermissionService,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences);
|
||||
|
||||
@@ -74,7 +76,6 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
const { route, contentManagementService, contentService, nodeActionsService, uploadService } = this;
|
||||
const { data } = route.snapshot;
|
||||
|
||||
this.routeData = data;
|
||||
this.title = data.i18nTitle;
|
||||
|
||||
route.params.subscribe(({ folderId }: Params) => {
|
||||
@@ -125,7 +126,7 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
return this.nodesApi.getNode(nodeId);
|
||||
}
|
||||
|
||||
fetchNodes(parentNodeId?: string, options: any = {}): Observable<NodePaging> {
|
||||
fetchNodes(parentNodeId?: string, options: { maxItems?: number, skipCount?: number } = {}): Observable<NodePaging> {
|
||||
const defaults = {
|
||||
include: [ 'isLocked', 'path', 'properties', 'allowableOperations' ]
|
||||
};
|
||||
@@ -202,23 +203,17 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
canCreateContent(parentNode: MinimalNodeEntryEntity): boolean {
|
||||
if (parentNode) {
|
||||
return this.contentService.hasPermission(parentNode, 'create');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
load(showIndicator: boolean = false, pagination: any = {}) {
|
||||
load(showIndicator: boolean = false, options: { maxItems?: number, skipCount?: number } = {}) {
|
||||
this.isLoading = showIndicator;
|
||||
|
||||
this.fetchNodes(this.getParentNodeId(), pagination)
|
||||
this.fetchNodes(this.getParentNodeId(), options)
|
||||
.flatMap((page) => {
|
||||
if (this.isCurrentPageEmpty(page) && this.isNotFirstPage(page)) {
|
||||
const newSkipCount = pagination.skipCount - pagination.maxItems;
|
||||
const newSkipCount = options.skipCount - options.maxItems;
|
||||
|
||||
return this.fetchNodes(this.getParentNodeId(), {skipCount: newSkipCount, maxItems: pagination.maxItems});
|
||||
return this.fetchNodes(this.getParentNodeId(), {
|
||||
skipCount: newSkipCount, maxItems: options.maxItems
|
||||
});
|
||||
}
|
||||
|
||||
return Observable.of(page);
|
||||
@@ -313,6 +308,13 @@ export class FilesComponent extends PageComponent implements OnInit, OnDestroy {
|
||||
this.preferences.set(`${this.prefix}.sorting.direction`, event.detail.direction || 'desc');
|
||||
}
|
||||
|
||||
openSnackMessage(event: any) {
|
||||
this.notificationService.openSnackMessage(
|
||||
event,
|
||||
4000
|
||||
);
|
||||
}
|
||||
|
||||
private get prefix() {
|
||||
return this.route.snapshot.data.preferencePrefix;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
@import 'variables';
|
||||
|
||||
$alfresco-warn-color--hue-2: #ff5252;
|
||||
|
||||
.generic-error {
|
||||
color: $alfresco-secondary-text-color;
|
||||
display: flex;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<adf-toolbar class="app-menu" [style.background-color]="backgroundColor">
|
||||
<adf-toolbar-title>
|
||||
<button mat-icon-button (click)="toggleMenu()">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
|
||||
<a class="app-menu__title"
|
||||
title="{{ appName }}"
|
||||
[routerLink]="[ '/' ]">
|
||||
@@ -7,7 +11,7 @@
|
||||
</a>
|
||||
</adf-toolbar-title>
|
||||
|
||||
<app-search></app-search>
|
||||
<app-search-input></app-search-input>
|
||||
|
||||
<adf-toolbar-divider></adf-toolbar-divider>
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
@import 'variables';
|
||||
|
||||
$app-menu-height: 64px;
|
||||
|
||||
.app-menu {
|
||||
height: $app-menu-height;
|
||||
|
||||
&.adf-toolbar {
|
||||
.mat-toolbar {
|
||||
@@ -26,12 +29,20 @@
|
||||
background-color: $alfresco-white !important;
|
||||
}
|
||||
}
|
||||
|
||||
.adf-toolbar-title {
|
||||
color: $alfresco-white;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.app-menu__title {
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
margin-left: 5px;
|
||||
margin-left: 40px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
*/
|
||||
|
||||
import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { Component, ViewEncapsulation, SecurityContext } from '@angular/core';
|
||||
import { Component, Output, EventEmitter, ViewEncapsulation, SecurityContext } from '@angular/core';
|
||||
import { AppConfigService } from '@alfresco/adf-core';
|
||||
|
||||
@Component({
|
||||
@@ -34,6 +34,8 @@ import { AppConfigService } from '@alfresco/adf-core';
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class HeaderComponent {
|
||||
@Output() menu: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
private defaultPath = '/assets/images/alfresco-logo-white.svg';
|
||||
private defaultBackgroundColor = '#2196F3';
|
||||
|
||||
@@ -42,6 +44,10 @@ export class HeaderComponent {
|
||||
private sanitizer: DomSanitizer
|
||||
) {}
|
||||
|
||||
toggleMenu() {
|
||||
this.menu.emit();
|
||||
}
|
||||
|
||||
get appName(): string {
|
||||
return <string>this.appConfig.get('application.name');
|
||||
}
|
||||
|
||||
@@ -1,14 +1,37 @@
|
||||
<div class="layout">
|
||||
<adf-upload-drag-area
|
||||
[parentId]="node?.id"
|
||||
[disabled]="!canCreateContent(node)">
|
||||
<app-header></app-header>
|
||||
[disabled]="!permission.check(node, ['create'])">
|
||||
|
||||
<div class="layout__content">
|
||||
<app-sidenav class="layout__content-side"></app-sidenav>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<adf-sidenav-layout
|
||||
[sidenavMin]="70"
|
||||
[sidenavMax]="320"
|
||||
[stepOver]="600"
|
||||
[hideSidenav]="isPreview"
|
||||
[expandedSidenav]="true">
|
||||
|
||||
<adf-sidenav-layout-header>
|
||||
<ng-template let-toggleMenu="toggleMenu">
|
||||
|
||||
<app-header (menu)="toggleMenu()"></app-header>
|
||||
|
||||
</ng-template>
|
||||
</adf-sidenav-layout-header>
|
||||
|
||||
<adf-sidenav-layout-navigation>
|
||||
<ng-template let-isMenuMinimized="isMenuMinimized">
|
||||
<app-sidenav [showLabel]="!isMenuMinimized()"></app-sidenav>
|
||||
</ng-template>
|
||||
</adf-sidenav-layout-navigation>
|
||||
|
||||
<adf-sidenav-layout-content>
|
||||
<ng-template>
|
||||
<router-outlet></router-outlet>
|
||||
</ng-template>
|
||||
</adf-sidenav-layout-content>
|
||||
|
||||
</adf-sidenav-layout>
|
||||
|
||||
<adf-file-uploading-dialog position="left"></adf-file-uploading-dialog>
|
||||
</adf-upload-drag-area>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,8 +1,4 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
router-outlet {
|
||||
flex: 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import {
|
||||
ContentService, PeopleContentService, AppConfigService,
|
||||
PeopleContentService, AppConfigService,
|
||||
AuthenticationService, UserPreferencesService, TranslationService,
|
||||
TranslationMock, StorageService, AlfrescoApiService, CookieService,
|
||||
LogService
|
||||
@@ -38,14 +38,13 @@ import {
|
||||
import { Observable } from 'rxjs/Observable';
|
||||
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { LayoutComponent } from './layout.component';
|
||||
|
||||
describe('LayoutComponent', () => {
|
||||
let fixture: ComponentFixture<LayoutComponent>;
|
||||
let component: LayoutComponent;
|
||||
let browsingFilesService: BrowsingFilesService;
|
||||
let contentService: ContentService;
|
||||
let node;
|
||||
const navItem = {
|
||||
label: 'some-label',
|
||||
route: {
|
||||
@@ -54,8 +53,6 @@ describe('LayoutComponent', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
node = { id: 'node-id' };
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
@@ -73,8 +70,8 @@ describe('LayoutComponent', () => {
|
||||
LogService,
|
||||
UserPreferencesService,
|
||||
AuthenticationService,
|
||||
ContentService,
|
||||
AppConfigService,
|
||||
NodePermissionService,
|
||||
BrowsingFilesService,
|
||||
{
|
||||
provide: PeopleContentService,
|
||||
@@ -89,7 +86,6 @@ describe('LayoutComponent', () => {
|
||||
fixture = TestBed.createComponent(LayoutComponent);
|
||||
component = fixture.componentInstance;
|
||||
browsingFilesService = TestBed.get(BrowsingFilesService);
|
||||
contentService = TestBed.get(ContentService);
|
||||
|
||||
const appConfig = TestBed.get(AppConfigService);
|
||||
spyOn(appConfig, 'get').and.returnValue([navItem]);
|
||||
@@ -104,28 +100,4 @@ describe('LayoutComponent', () => {
|
||||
|
||||
expect(component.node).toEqual(currentNode);
|
||||
});
|
||||
|
||||
describe('canCreateContent()', () => {
|
||||
it('returns true if node has permission', () => {
|
||||
spyOn(contentService, 'hasPermission').and.returnValue(true);
|
||||
|
||||
const permission = component.canCreateContent(<any>{});
|
||||
|
||||
expect(permission).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false if node does not have permission', () => {
|
||||
spyOn(contentService, 'hasPermission').and.returnValue(false);
|
||||
|
||||
const permission = component.canCreateContent(<any>{});
|
||||
|
||||
expect(permission).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false if node is null', () => {
|
||||
const permission = component.canCreateContent(null);
|
||||
|
||||
expect(permission).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,10 +24,11 @@
|
||||
*/
|
||||
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
import { Router, NavigationEnd } from '@angular/router';
|
||||
import { Subscription } from 'rxjs/Rx';
|
||||
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
import { ContentService } from '@alfresco/adf-core';
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-layout',
|
||||
@@ -36,12 +37,20 @@ import { BrowsingFilesService } from '../../common/services/browsing-files.servi
|
||||
})
|
||||
export class LayoutComponent implements OnInit, OnDestroy {
|
||||
node: MinimalNodeEntryEntity;
|
||||
isPreview = false;
|
||||
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(
|
||||
private contentService: ContentService,
|
||||
private browsingFilesService: BrowsingFilesService) {}
|
||||
private router: Router,
|
||||
private browsingFilesService: BrowsingFilesService,
|
||||
public permission: NodePermissionService) {
|
||||
this.router.events
|
||||
.filter(event => event instanceof NavigationEnd)
|
||||
.subscribe( (event: any ) => {
|
||||
this.isPreview = event.urlAfterRedirects.includes('preview');
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.subscriptions.concat([
|
||||
@@ -52,11 +61,4 @@ export class LayoutComponent implements OnInit, OnDestroy {
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach(s => s.unsubscribe());
|
||||
}
|
||||
|
||||
canCreateContent(node: MinimalNodeEntryEntity): boolean {
|
||||
if (node) {
|
||||
return this.contentService.hasPermission(node, 'create');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,68 +7,72 @@
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__content">
|
||||
<div class="inner-layout__panel" [ngClass]="{'adf-document-list--loading': isLoading}">
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'adf-document-list--empty' : ''"
|
||||
currentFolderId="-mysites-"
|
||||
selectionMode="none"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event)">
|
||||
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
|
||||
currentFolderId="-mysites-"
|
||||
selectionMode="none"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="group_work"
|
||||
title="APP.BROWSE.LIBRARIES.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.LIBRARIES.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="title"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.TITLE">
|
||||
<ng-template let-context>
|
||||
<span class="adf-datatable-cell" title="{{ makeLibraryTooltip(context.row.obj.entry) }}">
|
||||
{{ makeLibraryTitle(context.row.obj.entry) }}
|
||||
</span>
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="group_work"
|
||||
title="APP.BROWSE.LIBRARIES.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.LIBRARIES.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-column
|
||||
key="visibility"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.STATUS">
|
||||
<ng-template let-value="value">
|
||||
<span *ngIf="(value == 'PUBLIC')" title="{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }}">
|
||||
{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }}
|
||||
</span>
|
||||
<span *ngIf="(value == 'PRIVATE')" title="{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}">
|
||||
{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}
|
||||
</span>
|
||||
<span *ngIf="(value == 'MODERATED')" title="{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}">
|
||||
{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="title"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.TITLE">
|
||||
<ng-template let-context>
|
||||
<span class="adf-datatable-cell" title="{{ makeLibraryTooltip(context.row.obj.entry) }}">
|
||||
{{ makeLibraryTitle(context.row.obj.entry) }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="visibility"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.STATUS">
|
||||
<ng-template let-value="value">
|
||||
<span *ngIf="(value == 'PUBLIC')" title="{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }}">
|
||||
{{ 'APP.SITES_VISIBILITY.PUBLIC' | translate }}
|
||||
</span>
|
||||
<span *ngIf="(value == 'PRIVATE')" title="{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}">
|
||||
{{ 'APP.SITES_VISIBILITY.PRIVATE' | translate }}
|
||||
</span>
|
||||
<span *ngIf="(value == 'MODERATED')" title="{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}">
|
||||
{{ 'APP.SITES_VISIBILITY.MODERATED' | translate }}
|
||||
</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
|
||||
<ng-container *ngIf="!documentList.isEmpty()">
|
||||
<adf-pagination
|
||||
[supportedPageSizes]="'pagination.supportedPageSizes' | appConfig"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -36,12 +36,13 @@ import {
|
||||
StorageService, CookieService, ThumbnailService, AuthenticationService,
|
||||
TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent
|
||||
} from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ShareDataTableAdapter } from '@alfresco/adf-content-services';
|
||||
import { AppConfigPipe } from '../../common/pipes/app-config.pipe';
|
||||
|
||||
import { LibrariesComponent } from './libraries.component';
|
||||
|
||||
@@ -87,7 +88,8 @@ describe('Libraries Routed Component', () => {
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
DocumentListComponent,
|
||||
LibrariesComponent
|
||||
LibrariesComponent,
|
||||
AppConfigPipe
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: {
|
||||
@@ -103,7 +105,8 @@ describe('Libraries Routed Component', () => {
|
||||
ContentService,
|
||||
NodesApiService,
|
||||
DocumentListService,
|
||||
ThumbnailService
|
||||
ThumbnailService,
|
||||
CustomResourcesService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
})
|
||||
@@ -113,6 +116,7 @@ describe('Libraries Routed Component', () => {
|
||||
|
||||
nodesApi = TestBed.get(NodesApiService);
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
alfrescoApi.reset();
|
||||
router = TestBed.get(Router);
|
||||
preferenceService = TestBed.get(UserPreferencesService);
|
||||
});
|
||||
@@ -191,8 +195,6 @@ describe('Libraries Routed Component', () => {
|
||||
|
||||
component.navigate(node.id);
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(routerSpy.calls.argsFor(0)[0]).toEqual(['./', document.id]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,7 +39,7 @@ import { Observable } from 'rxjs/Rx';
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
// tslint:disable-next-line:use-host-property-decorator
|
||||
host: {
|
||||
'class': 'app-location-link'
|
||||
'class': 'app-location-link adf-location-cell'
|
||||
}
|
||||
})
|
||||
export class LocationLinkComponent implements OnInit {
|
||||
|
||||
@@ -104,7 +104,7 @@ describe('PageComponent', () => {
|
||||
});
|
||||
|
||||
it('sets component pagination data', () => {
|
||||
expect(component.pagination).toBe(page.list.pagination);
|
||||
expect(component.pagination).toEqual(page.list.pagination);
|
||||
});
|
||||
|
||||
it('sets component isEmpty state', () => {
|
||||
@@ -299,51 +299,21 @@ describe('PageComponent', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('canDeleteShared()', () => {
|
||||
it('should return true if shared node can be deleted', () => {
|
||||
describe('canUpdate()', () => {
|
||||
it('should return true if node can be edited', () => {
|
||||
const selection = [ { entry: {
|
||||
allowableOperationsOnTarget: ['delete']
|
||||
allowableOperations: ['update']
|
||||
} } ];
|
||||
|
||||
expect(component.canDeleteShared(selection)).toBe(true);
|
||||
expect(component.canUpdate(selection)).toBe(true);
|
||||
});
|
||||
|
||||
it(`should return false if shared node doesn't have permission`, () => {
|
||||
it(`should return false if node cannot be edited`, () => {
|
||||
const selection = [ { entry: {
|
||||
allowableOperationsOnTarget: ['something']
|
||||
allowableOperations: ['other-permission']
|
||||
} } ];
|
||||
|
||||
expect(component.canDeleteShared(selection)).toBe(false);
|
||||
});
|
||||
|
||||
it(`should return false if shared node doesn't have permissions property`, () => {
|
||||
const selection = [ { entry: { } } ];
|
||||
|
||||
expect(component.canDeleteShared(selection)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('canMoveShared()', () => {
|
||||
it('should return true if shared node can be moved', () => {
|
||||
const selection = [ { entry: {
|
||||
allowableOperationsOnTarget: ['delete']
|
||||
} } ];
|
||||
|
||||
expect(component.canMoveShared(selection)).toBe(true);
|
||||
});
|
||||
|
||||
it(`should return false if shared node doesn't have permission`, () => {
|
||||
const selection = [ { entry: {
|
||||
allowableOperationsOnTarget: ['something']
|
||||
} } ];
|
||||
|
||||
expect(component.canMoveShared(selection)).toBe(false);
|
||||
});
|
||||
|
||||
it(`should return false if shared node doesn't have permissions property`, () => {
|
||||
const selection = [ { entry: { } } ];
|
||||
|
||||
expect(component.canMoveShared(selection)).toBe(false);
|
||||
expect(component.canUpdate(selection)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,6 +33,7 @@ export abstract class PageComponent {
|
||||
|
||||
isLoading = false;
|
||||
isEmpty = true;
|
||||
infoDrawerOpened = false;
|
||||
|
||||
paging: NodePaging;
|
||||
pagination: Pagination;
|
||||
@@ -63,7 +64,7 @@ export abstract class PageComponent {
|
||||
onPageLoaded(page: NodePaging) {
|
||||
this.isLoading = false;
|
||||
this.paging = page;
|
||||
this.pagination = page.list.pagination;
|
||||
this.pagination = { ...page.list.pagination };
|
||||
this.isEmpty = !(page.list.entries && page.list.entries.length > 0);
|
||||
}
|
||||
|
||||
@@ -111,16 +112,12 @@ export abstract class PageComponent {
|
||||
return selection.every(node => node.entry && this.nodeHasPermission(node.entry, 'delete'));
|
||||
}
|
||||
|
||||
canDeleteShared(selection: Array<MinimalNodeEntity> = []): boolean {
|
||||
return selection.every(node => node.entry && this.nodeSharedHasPermission(node.entry, 'delete'));
|
||||
}
|
||||
|
||||
canMove(selection: Array<MinimalNodeEntity>): boolean {
|
||||
return this.canDelete(selection);
|
||||
}
|
||||
|
||||
canMoveShared(selection: Array<MinimalNodeEntity> = []): boolean {
|
||||
return selection.every(node => node.entry && this.nodeSharedHasPermission(node.entry, 'delete'));
|
||||
canUpdate(selection: Array<MinimalNodeEntity> = []): boolean {
|
||||
return selection.every(node => node.entry && this.nodeHasPermission(node.entry, 'update'));
|
||||
}
|
||||
|
||||
canPreviewFile(selection: Array<MinimalNodeEntity>): boolean {
|
||||
@@ -135,6 +132,14 @@ export abstract class PageComponent {
|
||||
return this.isFileSelected(selection);
|
||||
}
|
||||
|
||||
canUpdateFile(selection: Array<MinimalNodeEntity>): boolean {
|
||||
return this.isFileSelected(selection) && this.nodeHasPermission(selection[0].entry, 'update');
|
||||
}
|
||||
|
||||
canManageVersions(selection: Array<MinimalNodeEntity>): boolean {
|
||||
return this.canUpdateFile(selection);
|
||||
}
|
||||
|
||||
nodeHasPermission(node: MinimalNodeEntryEntity, permission: string): boolean {
|
||||
if (node && permission) {
|
||||
const { allowableOperations = [] } = <any>(node || {});
|
||||
@@ -147,18 +152,6 @@ export abstract class PageComponent {
|
||||
return false;
|
||||
}
|
||||
|
||||
nodeSharedHasPermission(node: MinimalNodeEntryEntity, permission: string): boolean {
|
||||
if (node && permission) {
|
||||
const { allowableOperationsOnTarget } = <any>(node || {});
|
||||
|
||||
if (allowableOperationsOnTarget && allowableOperationsOnTarget.indexOf(permission) > -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
onChangePageSize(event: Pagination): void {
|
||||
this.preferences.paginationSize = event.maxItems;
|
||||
}
|
||||
@@ -204,4 +197,11 @@ export abstract class PageComponent {
|
||||
return null;
|
||||
}
|
||||
|
||||
toggleSidebar(event) {
|
||||
if (event) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.infoDrawerOpened = !this.infoDrawerOpened;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,29 @@
|
||||
<ng-container *ngIf="nodeId">
|
||||
|
||||
<ng-template #sidebarTemplate>
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(node, ['update'])"
|
||||
[displayEmpty]="permission.check(node, ['update'])"
|
||||
[preset]="'custom'"
|
||||
[node]="node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container>
|
||||
<adf-version-manager [node]="node"></adf-version-manager>
|
||||
</ng-container>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
</ng-template>
|
||||
|
||||
<adf-viewer
|
||||
[fileNodeId]="nodeId"
|
||||
[allowNavigate]="navigateMultiple"
|
||||
[allowSidebar]="true"
|
||||
[sidebarTemplate]="sidebarTemplate"
|
||||
[canNavigateBefore]="previousNodeId"
|
||||
[canNavigateNext]="nextNodeId"
|
||||
[overlayMode]="true"
|
||||
@@ -15,7 +37,10 @@
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="selectedEntities">
|
||||
<mat-icon [ngClass]="{ 'icon-highlight': selection.hasFavorites() }">
|
||||
<mat-icon [ngClass]="{
|
||||
'toolbar__option--active': selection.hasFavorites(),
|
||||
'toolbar__option--default': !selection.hasFavorites()
|
||||
}">
|
||||
{{ selection.hasFavorites() ? 'star' :'star_border' }}
|
||||
</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@@ -23,28 +48,34 @@
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canCopyFile()"
|
||||
[app-copy-node]="selectedEntities">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<mat-icon color="primary">content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canMoveFile()"
|
||||
*ngIf="permission.check(node, ['delete'])"
|
||||
[app-move-node]="selectedEntities">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<mat-icon color="primary">library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canDeleteFile()"
|
||||
*ngIf="permission.check(node, ['delete'])"
|
||||
(click)="deleteFile()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<mat-icon color="primary">delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(node, ['update'])"
|
||||
[app-node-versions]="selectedEntities">
|
||||
<mat-icon color="primary">history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
</adf-viewer-more-actions>
|
||||
</adf-viewer>
|
||||
</ng-container>
|
||||
|
||||
@@ -36,6 +36,7 @@ import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
import { PreviewComponent } from './preview.component';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { MatSnackBarModule } from '@angular/material';
|
||||
|
||||
@@ -64,6 +65,7 @@ describe('PreviewComponent', () => {
|
||||
CookieService,
|
||||
NotificationService,
|
||||
UserPreferencesService,
|
||||
NodePermissionService,
|
||||
ContentManagementService
|
||||
],
|
||||
declarations: [
|
||||
@@ -79,6 +81,7 @@ describe('PreviewComponent', () => {
|
||||
router = TestBed.get(Router);
|
||||
route = TestBed.get(ActivatedRoute);
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
alfrescoApi.reset();
|
||||
preferences = TestBed.get(UserPreferencesService);
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -27,6 +27,7 @@ import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { AlfrescoApiService, UserPreferencesService, ObjectUtils } from '@alfresco/adf-core';
|
||||
import { Node, MinimalNodeEntity } from 'alfresco-js-api';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
|
||||
@Component({
|
||||
@@ -54,10 +55,11 @@ export class PreviewComponent implements OnInit {
|
||||
selectedEntities: MinimalNodeEntity[] = [];
|
||||
|
||||
constructor(private router: Router,
|
||||
private route: ActivatedRoute,
|
||||
private apiService: AlfrescoApiService,
|
||||
private preferences: UserPreferencesService,
|
||||
private content: ContentManagementService) {
|
||||
private route: ActivatedRoute,
|
||||
private apiService: AlfrescoApiService,
|
||||
private preferences: UserPreferencesService,
|
||||
private content: ContentManagementService,
|
||||
public permission: NodePermissionService) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -324,10 +326,6 @@ export class PreviewComponent implements OnInit {
|
||||
return path;
|
||||
}
|
||||
|
||||
canDeleteFile(): boolean {
|
||||
return this.content.canDeleteNode(this.node);
|
||||
}
|
||||
|
||||
async deleteFile() {
|
||||
try {
|
||||
await this.content.deleteNode(this.node);
|
||||
@@ -335,12 +333,4 @@ export class PreviewComponent implements OnInit {
|
||||
} catch {
|
||||
}
|
||||
}
|
||||
|
||||
canMoveFile(): boolean {
|
||||
return this.content.canMoveNode(this.node);
|
||||
}
|
||||
|
||||
canCopyFile(): boolean {
|
||||
return this.content.canCopyNode(this.node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="canPreviewFile(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
(click)="onNodeDoubleClick(documentList.selection[0]?.entry)">
|
||||
@@ -15,19 +16,30 @@
|
||||
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
[adfNodeDownload]="documentList.selection">
|
||||
<mat-icon>get_app</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="documentList.selection.length"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
[matMenuTriggerFor]="actionsMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #actionsMenu="matMenu"
|
||||
[overlapTrigger]="false"
|
||||
class="secondary-options">
|
||||
@@ -35,7 +47,10 @@
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
<mat-icon [ngClass]="{ 'icon-highlight': selection.hasFavorites() }">
|
||||
<mat-icon [ngClass]="{
|
||||
'toolbar__option--active': selection.hasFavorites(),
|
||||
'toolbar__option--default': !selection.hasFavorites()
|
||||
}">
|
||||
{{ selection.hasFavorites() ? 'star' :'star_border' }}
|
||||
</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@@ -44,7 +59,7 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
[app-copy-node]="documentList.selection">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<mat-icon color="primary">content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
@@ -52,7 +67,7 @@
|
||||
mat-menu-item
|
||||
*ngIf="canMove(documentList.selection)"
|
||||
[app-move-node]="documentList.selection">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<mat-icon color="primary">library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
@@ -60,82 +75,132 @@
|
||||
mat-menu-item
|
||||
*ngIf="canDelete(documentList.selection)"
|
||||
[app-delete-node]="documentList.selection">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<mat-icon color="primary">delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canManageVersions(documentList.selection)"
|
||||
[app-node-versions]="documentList.selection">
|
||||
<mat-icon color="primary">history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</adf-toolbar>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__content">
|
||||
<div class="inner-layout__panel" [ngClass]="{'adf-document-list--loading': documentList.isEmpty()}">
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'adf-document-list--empty' : ''"
|
||||
currentFolderId="-recent-"
|
||||
selectionMode="multiple"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
[imageResolver]="imageResolver"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"
|
||||
(node-select)="onNodeSelect($event, documentList)">
|
||||
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
|
||||
currentFolderId="-recent-"
|
||||
selectionMode="multiple"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
[imageResolver]="imageResolver"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)"
|
||||
(node-select)="onNodeSelect($event, documentList)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="access_time"
|
||||
title="APP.BROWSE.RECENT.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.RECENT.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="access_time"
|
||||
title="APP.BROWSE.RECENT.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.RECENT.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
type="fileSize"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
|
||||
</adf-document-list>
|
||||
|
||||
<ng-container *ngIf="!documentList.isEmpty()">
|
||||
<adf-pagination
|
||||
[supportedPageSizes]="'pagination.supportedPageSizes' | appConfig"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[app-node-info]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!canUpdate(documentList.selection)"
|
||||
[displayEmpty]="canUpdate(documentList.selection)"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="isFileSelected(documentList.selection);else choose_document_template">
|
||||
<adf-version-manager
|
||||
*ngIf="infoInstance.node"
|
||||
[node]="infoInstance.node">
|
||||
</adf-version-manager>
|
||||
</ng-container>
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
type="fileSize"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</data-columns>
|
||||
|
||||
</adf-document-list>
|
||||
<adf-pagination [ngClass]="{'no-border' : documentList.isEmpty()}"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,12 +35,14 @@ import {
|
||||
StorageService, CookieService, ThumbnailService, AuthenticationService,
|
||||
TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective, DataTableComponent
|
||||
} from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
import { AppConfigPipe } from '../../common/pipes/app-config.pipe';
|
||||
|
||||
import { RecentFilesComponent } from './recent-files.component';
|
||||
|
||||
@@ -52,7 +54,6 @@ describe('RecentFiles Routed Component', () => {
|
||||
let contentService: ContentManagementService;
|
||||
let preferenceService: UserPreferencesService;
|
||||
let page;
|
||||
let person;
|
||||
|
||||
beforeEach(() => {
|
||||
page = {
|
||||
@@ -61,8 +62,6 @@ describe('RecentFiles Routed Component', () => {
|
||||
pagination: { data: 'data'}
|
||||
}
|
||||
};
|
||||
|
||||
person = { entry: { id: 'bogus' } };
|
||||
});
|
||||
|
||||
beforeEach(async(() => {
|
||||
@@ -80,8 +79,10 @@ describe('RecentFiles Routed Component', () => {
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
RecentFilesComponent
|
||||
RecentFilesComponent,
|
||||
AppConfigPipe
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: {
|
||||
@@ -98,7 +99,8 @@ describe('RecentFiles Routed Component', () => {
|
||||
ContentService,
|
||||
NodesApiService,
|
||||
DocumentListService,
|
||||
ThumbnailService
|
||||
ThumbnailService,
|
||||
CustomResourcesService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
})
|
||||
@@ -110,6 +112,7 @@ describe('RecentFiles Routed Component', () => {
|
||||
contentService = TestBed.get(ContentManagementService);
|
||||
preferenceService = TestBed.get(UserPreferencesService);
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
alfrescoApi.reset();
|
||||
});
|
||||
}));
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<adf-search-control
|
||||
[highlight]="true"
|
||||
(optionClicked)="onItemClicked($event)"
|
||||
(submit)="onSearchSubmit($event)">
|
||||
</adf-search-control>
|
||||
@@ -0,0 +1,10 @@
|
||||
@import 'variables';
|
||||
|
||||
// todo: remove once ADF 2.0 is out
|
||||
:host {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
adf-search-control {
|
||||
color: $alfresco-white;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { Router } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { SearchInputComponent } from './search-input.component';
|
||||
|
||||
describe('SearchInputComponent', () => {
|
||||
let fixture;
|
||||
let component;
|
||||
let router: Router;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
SearchInputComponent
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
})
|
||||
.compileComponents()
|
||||
.then(() => {
|
||||
fixture = TestBed.createComponent(SearchInputComponent);
|
||||
component = fixture.componentInstance;
|
||||
router = TestBed.get(Router);
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
|
||||
describe('onItemClicked()', () => {
|
||||
it('opens preview if node is file', () => {
|
||||
spyOn(router, 'navigate').and.stub();
|
||||
const node = { entry: { isFile: true, id: 'node-id', parentId: 'parent-id' } };
|
||||
|
||||
component.onItemClicked(node);
|
||||
|
||||
expect(router.navigate['calls'].argsFor(0)[0])
|
||||
.toEqual([`/personal-files/${node.entry.parentId}/preview/`, node.entry.id]);
|
||||
});
|
||||
|
||||
it('navigates if node is folder', () => {
|
||||
const node = { entry: { isFolder: true } };
|
||||
spyOn(router, 'navigate');
|
||||
|
||||
component.onItemClicked(node);
|
||||
|
||||
expect(router.navigate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
+35
-22
@@ -23,27 +23,40 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import {
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
MatInputModule
|
||||
} from '@angular/material';
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
|
||||
export function modules() {
|
||||
return [
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
MatButtonModule,
|
||||
MatDialogModule,
|
||||
MatInputModule
|
||||
];
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: modules(),
|
||||
exports: modules()
|
||||
@Component({
|
||||
selector: 'app-search-input',
|
||||
templateUrl: 'search-input.component.html',
|
||||
styleUrls: ['search-input.component.scss']
|
||||
})
|
||||
export class MaterialModule {}
|
||||
export class SearchInputComponent {
|
||||
|
||||
constructor(
|
||||
private router: Router) {
|
||||
}
|
||||
|
||||
onItemClicked(node: MinimalNodeEntity) {
|
||||
if (node && node.entry) {
|
||||
if (node.entry.isFile) {
|
||||
this.router.navigate([`/personal-files/${node.entry.parentId}/preview/`, node.entry.id]);
|
||||
} else if (node.entry.isFolder) {
|
||||
this.router.navigate([ '/personal-files', node.entry.id ]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user submits the search, e.g. hits enter or clicks submit
|
||||
*
|
||||
* @param event Parameters relating to the search
|
||||
*/
|
||||
onSearchSubmit(event: KeyboardEvent) {
|
||||
const value = (event.target as HTMLInputElement).value;
|
||||
this.router.navigate(['/search', {
|
||||
q: value
|
||||
}]);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,32 @@
|
||||
<adf-search-control
|
||||
[highlight]="true"
|
||||
(optionClicked)="onItemClicked($event)">
|
||||
</adf-search-control>
|
||||
<adf-search
|
||||
#search
|
||||
[searchTerm]="searchedWord"
|
||||
[maxResults]="maxItems"
|
||||
[skipResults]="skipCount"
|
||||
(resultLoaded)="onSearchResultLoaded($event)">
|
||||
</adf-search>
|
||||
|
||||
<div class="adf-search-results__facets">
|
||||
<adf-search-chip-list
|
||||
[searchFilter]="searchFilter">
|
||||
</adf-search-chip-list>
|
||||
</div>
|
||||
|
||||
<div class="adf-search-results">
|
||||
<adf-search-filter
|
||||
#searchFilter>
|
||||
</adf-search-filter>
|
||||
|
||||
<div class="adf-search-results__content">
|
||||
<adf-document-list
|
||||
#documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'adf-document-list--empty' : ''"
|
||||
[node]="data">
|
||||
</adf-document-list>
|
||||
|
||||
<adf-pagination *ngIf="!documentList.isEmpty()"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onRefreshPagination($event)">
|
||||
</adf-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,26 @@
|
||||
@import 'variables';
|
||||
@import 'mixins';
|
||||
|
||||
// todo: remove once ADF 2.0 is out
|
||||
:host {
|
||||
overflow: hidden;
|
||||
}
|
||||
.adf-search-results {
|
||||
@include flex-row;
|
||||
|
||||
adf-search-control {
|
||||
color: $alfresco-white;
|
||||
&__facets {
|
||||
display: flex;
|
||||
height: 35px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
padding: 5px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
&__content {
|
||||
@include flex-column;
|
||||
border-left: 1px solid #eee;
|
||||
}
|
||||
|
||||
.adf-search-filter {
|
||||
min-width: 260px;
|
||||
padding: 5px;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,78 +1,25 @@
|
||||
/*!
|
||||
* @license
|
||||
* Alfresco Example Content Application
|
||||
*
|
||||
* Copyright (C) 2005 - 2018 Alfresco Software Limited
|
||||
*
|
||||
* This file is part of the Alfresco Example Content Application.
|
||||
* If the software was purchased under a paid Alfresco license, the terms of
|
||||
* the paid license agreement will prevail. Otherwise, the software is
|
||||
* provided under the following open source license terms:
|
||||
*
|
||||
* The Alfresco Example Content Application is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* The Alfresco Example Content Application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { Router } from '@angular/router';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SearchComponent } from './search.component';
|
||||
|
||||
describe('SearchComponent', () => {
|
||||
let fixture;
|
||||
let component;
|
||||
let router: Router;
|
||||
let component: SearchComponent;
|
||||
let fixture: ComponentFixture<SearchComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
SearchComponent
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
})
|
||||
.compileComponents()
|
||||
.then(() => {
|
||||
fixture = TestBed.createComponent(SearchComponent);
|
||||
component = fixture.componentInstance;
|
||||
router = TestBed.get(Router);
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SearchComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
fixture.detectChanges();
|
||||
});
|
||||
}));
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SearchComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('onItemClicked()', () => {
|
||||
it('opens preview if node is file', () => {
|
||||
spyOn(router, 'navigate').and.stub();
|
||||
const node = { entry: { isFile: true, id: 'node-id', parentId: 'parent-id' } };
|
||||
|
||||
component.onItemClicked(node);
|
||||
|
||||
expect(router.navigate['calls'].argsFor(0)[0])
|
||||
.toEqual([`/personal-files/${node.entry.parentId}/preview/`, node.entry.id]);
|
||||
});
|
||||
|
||||
it('navigates if node is folder', () => {
|
||||
const node = { entry: { isFolder: true } };
|
||||
spyOn(router, 'navigate');
|
||||
|
||||
component.onItemClicked(node);
|
||||
|
||||
expect(router.navigate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
xit('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -23,28 +23,59 @@
|
||||
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { MinimalNodeEntity } from 'alfresco-js-api';
|
||||
import { Component, OnInit, Optional, ViewChild } from '@angular/core';
|
||||
import { NodePaging, Pagination } from 'alfresco-js-api';
|
||||
import { Router, ActivatedRoute, Params } from '@angular/router';
|
||||
import { SearchQueryBuilderService, SearchComponent as AdfSearchComponent } from '@alfresco/adf-content-services';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
templateUrl: 'search.component.html',
|
||||
styleUrls: ['search.component.scss']
|
||||
selector: 'app-search',
|
||||
templateUrl: './search.component.html',
|
||||
styleUrls: ['./search.component.scss']
|
||||
})
|
||||
export class SearchComponent {
|
||||
export class SearchComponent implements OnInit {
|
||||
|
||||
@ViewChild('search')
|
||||
search: AdfSearchComponent;
|
||||
|
||||
queryParamName = 'q';
|
||||
searchedWord = '';
|
||||
data: NodePaging;
|
||||
maxItems = 5;
|
||||
skipCount = 0;
|
||||
|
||||
constructor(
|
||||
private router: Router) {
|
||||
public router: Router,
|
||||
private queryBuilder: SearchQueryBuilderService,
|
||||
@Optional() private route: ActivatedRoute) {
|
||||
queryBuilder.paging = {
|
||||
skipCount: 0,
|
||||
maxItems: 25
|
||||
};
|
||||
}
|
||||
|
||||
onItemClicked(node: MinimalNodeEntity) {
|
||||
if (node && node.entry) {
|
||||
if (node.entry.isFile) {
|
||||
this.router.navigate([`/personal-files/${node.entry.parentId}/preview/`, node.entry.id]);
|
||||
} else if (node.entry.isFolder) {
|
||||
this.router.navigate([ '/personal-files', node.entry.id ]);
|
||||
}
|
||||
ngOnInit() {
|
||||
if (this.route) {
|
||||
this.route.params.forEach((params: Params) => {
|
||||
this.searchedWord = params.hasOwnProperty(this.queryParamName) ? params[this.queryParamName] : null;
|
||||
this.queryBuilder.queryFragments['queryName'] = `cm:name:'${this.searchedWord}'`;
|
||||
this.queryBuilder.update();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onSearchResultLoaded(nodePaging: NodePaging) {
|
||||
this.data = nodePaging;
|
||||
}
|
||||
|
||||
onRefreshPagination(pagination: Pagination) {
|
||||
this.maxItems = pagination.maxItems;
|
||||
this.skipCount = pagination.skipCount;
|
||||
|
||||
this.queryBuilder.paging = {
|
||||
maxItems: pagination.maxItems,
|
||||
skipCount: pagination.skipCount
|
||||
};
|
||||
this.queryBuilder.update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
</adf-breadcrumb>
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="canPreviewFile(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.VIEW' | translate }}"
|
||||
@@ -14,20 +14,31 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.DOWNLOAD' | translate }}"
|
||||
[adfNodeDownload]="documentList.selection">
|
||||
[appNodeDownload]="documentList.selection">
|
||||
<mat-icon>get_app</mat-icon>
|
||||
</button>
|
||||
|
||||
<button mat-icon-button
|
||||
[color]="infoDrawerOpened ? 'accent' : 'primary'"
|
||||
*ngIf="documentList.selection.length"
|
||||
title="{{ 'APP.ACTIONS.DETAILS' | translate }}"
|
||||
(click)="toggleSidebar()">
|
||||
<mat-icon>info_outline</mat-icon>
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
*ngIf="hasSelection(documentList.selection)"
|
||||
title="{{ 'APP.ACTIONS.MORE' | translate }}"
|
||||
[matMenuTriggerFor]="actionsMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #actionsMenu="matMenu"
|
||||
[overlapTrigger]="false"
|
||||
class="secondary-options">
|
||||
@@ -35,7 +46,10 @@
|
||||
mat-menu-item
|
||||
#selection="adfFavorite"
|
||||
[adf-node-favorite]="documentList.selection">
|
||||
<mat-icon [ngClass]="{ 'icon-highlight': selection.hasFavorites() }">
|
||||
<mat-icon [ngClass]="{
|
||||
'toolbar__option--active': selection.hasFavorites(),
|
||||
'toolbar__option--default': !selection.hasFavorites()
|
||||
}">
|
||||
{{ selection.hasFavorites() ? 'star' :'star_border' }}
|
||||
</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.FAVORITE' | translate }}</span>
|
||||
@@ -44,115 +58,166 @@
|
||||
<button
|
||||
mat-menu-item
|
||||
[app-copy-node]="documentList.selection">
|
||||
<mat-icon>content_copy</mat-icon>
|
||||
<mat-icon color="primary">content_copy</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.COPY' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canMoveShared(documentList.selection)"
|
||||
*ngIf="permission.check(documentList.selection, ['delete'], { target: 'allowableOperationsOnTarget' })"
|
||||
[app-move-node]="documentList.selection">
|
||||
<mat-icon>library_books</mat-icon>
|
||||
<mat-icon color="primary">library_books</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.MOVE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canDelete(documentList.selection)"
|
||||
*ngIf="permission.check(documentList.selection, ['delete'])"
|
||||
[appUnshareNode]="documentList.selection"
|
||||
(links-unshared)="refresh()">
|
||||
<mat-icon>stop_screen_share</mat-icon>
|
||||
<mat-icon color="primary">stop_screen_share</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.UNSHARE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="canDeleteShared(documentList.selection)"
|
||||
*ngIf="permission.check(documentList.selection, ['delete'], { target: 'allowableOperationsOnTarget' })"
|
||||
[app-delete-node]="documentList.selection">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<mat-icon color="primary">delete</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.DELETE' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
mat-menu-item
|
||||
*ngIf="permission.check(documentList.selection[0], ['update'], { target: 'allowableOperationsOnTarget' })"
|
||||
[app-node-versions]="documentList.selection">
|
||||
<mat-icon color="primary">history</mat-icon>
|
||||
<span>{{ 'APP.ACTIONS.VERSIONS' | translate }}</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</adf-toolbar>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__content">
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
|
||||
currentFolderId="-sharedlinks-"
|
||||
selectionMode="multiple"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
|
||||
<div class="inner-layout__panel" [ngClass]="{'adf-document-list--loading': documentList.isEmpty()}">
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'adf-document-list--empty' : ''"
|
||||
currentFolderId="-sharedlinks-"
|
||||
selectionMode="multiple"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)"
|
||||
(node-dblclick)="onNodeDoubleClick($event.detail?.node?.entry)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="people"
|
||||
title="APP.BROWSE.SHARED.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.SHARED.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="people"
|
||||
title="APP.BROWSE.SHARED.EMPTY_STATE.TITLE"
|
||||
subtitle="APP.BROWSE.SHARED.EMPTY_STATE.TEXT">
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
<data-columns>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
|
||||
type="fileSize">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="modifiedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="sharedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SHARED_BY">
|
||||
</data-column>
|
||||
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
|
||||
<ng-container *ngIf="!documentList.isEmpty()">
|
||||
<adf-pagination
|
||||
[supportedPageSizes]="'pagination.supportedPageSizes' | appConfig"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__side-panel"
|
||||
*ngIf="infoDrawerOpened"
|
||||
[app-node-info]="documentList.selection"
|
||||
(changed)="toggleSidebar($event)"
|
||||
#infoInstance=nodeInfo>
|
||||
|
||||
<adf-info-drawer [title]="'APP.INFO_DRAWER.TITLE' | translate">
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.PROPERTIES' | translate">
|
||||
<div *ngIf="infoInstance.loading">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
|
||||
<adf-content-metadata-card
|
||||
[readOnly]="!permission.check(documentList.selection, ['update'], { target: 'allowableOperationsOnTarget' })"
|
||||
[displayEmpty]="permission.check(documentList.selection, ['update'], { target: 'allowableOperationsOnTarget' })"
|
||||
[preset]="'custom'"
|
||||
[node]="infoInstance.node">
|
||||
</adf-content-metadata-card>
|
||||
</adf-info-drawer-tab>
|
||||
|
||||
<adf-info-drawer-tab [label]="'APP.INFO_DRAWER.TABS.VERSIONS' | translate">
|
||||
<ng-container *ngIf="isFileSelected(documentList.selection);else choose_document_template">
|
||||
<adf-version-manager
|
||||
*ngIf="infoInstance.node"
|
||||
[node]="infoInstance.node">
|
||||
</adf-version-manager>
|
||||
</ng-container>
|
||||
<ng-template #choose_document_template>
|
||||
<div class="adf-manage-versions-empty">
|
||||
<mat-icon class="adf-manage-versions-empty-icon">face</mat-icon>
|
||||
{{ 'VERSION.SELECTION.EMPTY' | translate }}
|
||||
</div>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
|
||||
type="fileSize">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="modifiedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="modifiedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.MODIFIED_BY">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="sharedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SHARED_BY">
|
||||
</data-column>
|
||||
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
<adf-pagination [ngClass]="{ 'no-border' :documentList.isEmpty()}"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</adf-info-drawer-tab>
|
||||
</adf-info-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,12 +35,15 @@ import {
|
||||
StorageService, CookieService, ThumbnailService, AuthenticationService,
|
||||
TimeAgoPipe, NodeNameTooltipPipe, NodeFavoriteDirective,DataTableComponent
|
||||
} from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
import { DocumentListComponent, CustomResourcesService } from '@alfresco/adf-content-services';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MatMenuModule, MatSnackBarModule, MatIconModule } from '@angular/material';
|
||||
import { DocumentListService } from '@alfresco/adf-content-services';
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodeInfoDirective } from '../../common/directives/node-info.directive';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { AppConfigPipe } from '../../common/pipes/app-config.pipe';
|
||||
|
||||
import { SharedFilesComponent } from './shared-files.component';
|
||||
|
||||
@@ -79,8 +82,10 @@ describe('SharedFilesComponent', () => {
|
||||
TimeAgoPipe,
|
||||
NodeNameTooltipPipe,
|
||||
NodeFavoriteDirective,
|
||||
NodeInfoDirective,
|
||||
DocumentListComponent,
|
||||
SharedFilesComponent
|
||||
SharedFilesComponent,
|
||||
AppConfigPipe
|
||||
],
|
||||
providers: [
|
||||
{ provide: ActivatedRoute, useValue: {
|
||||
@@ -94,10 +99,12 @@ describe('SharedFilesComponent', () => {
|
||||
LogService,
|
||||
NotificationService,
|
||||
ContentManagementService,
|
||||
NodePermissionService,
|
||||
ContentService,
|
||||
NodesApiService,
|
||||
DocumentListService,
|
||||
ThumbnailService
|
||||
ThumbnailService,
|
||||
CustomResourcesService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
})
|
||||
@@ -108,6 +115,7 @@ describe('SharedFilesComponent', () => {
|
||||
|
||||
contentService = TestBed.get(ContentManagementService);
|
||||
alfrescoApi = TestBed.get(AlfrescoApiService);
|
||||
alfrescoApi.reset();
|
||||
nodeService = alfrescoApi.getInstance().nodes;
|
||||
preferenceService = TestBed.get(UserPreferencesService);
|
||||
router = TestBed.get(Router);
|
||||
|
||||
@@ -31,6 +31,7 @@ import { AlfrescoApiService, UserPreferencesService } from '@alfresco/adf-core';
|
||||
import { DocumentListComponent } from '@alfresco/adf-content-services';
|
||||
|
||||
import { ContentManagementService } from '../../common/services/content-management.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
import { PageComponent } from '../page.component';
|
||||
|
||||
@Component({
|
||||
@@ -49,6 +50,7 @@ export class SharedFilesComponent extends PageComponent implements OnInit, OnDes
|
||||
private route: ActivatedRoute,
|
||||
private content: ContentManagementService,
|
||||
private apiService: AlfrescoApiService,
|
||||
public permission: NodePermissionService,
|
||||
preferences: UserPreferencesService) {
|
||||
super(preferences);
|
||||
|
||||
|
||||
@@ -1,32 +1,45 @@
|
||||
<div class="sidenav">
|
||||
<div class="sidenav__section sidenav__section--new">
|
||||
<button class="sidenav__section--new__button" mat-button [matMenuTriggerFor]="menu">
|
||||
<div class="sidenav__section sidenav__section--new" [ngClass]="{ 'section--new--mini': !showLabel }">
|
||||
<button *ngIf="showLabel"
|
||||
[matMenuTriggerFor]="menu"
|
||||
class="sidenav__section--new__button"
|
||||
[disableRipple]="true"
|
||||
mat-raised-button
|
||||
color="accent">
|
||||
|
||||
<span>{{ 'APP.NEW_MENU.LABEL' | translate }}</span>
|
||||
<mat-icon>arrow_drop_down</mat-icon>
|
||||
</button>
|
||||
|
||||
<button [matMenuTriggerFor]="menu"
|
||||
*ngIf="!showLabel"
|
||||
color="accent"
|
||||
mat-icon-button>
|
||||
<mat-icon>add_box</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-menu #menu="matMenu" [overlapTrigger]="false">
|
||||
<button
|
||||
mat-menu-item
|
||||
[disabled]="!canCreateContent(node)"
|
||||
[disabled]="!permission.check(node, ['create'])"
|
||||
(error)="openSnackMessage($event)"
|
||||
[adf-create-folder]="node?.id"
|
||||
title="{{
|
||||
( canCreateContent(node)
|
||||
[title]="
|
||||
( permission.check(node, ['create'])
|
||||
? 'APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER'
|
||||
: 'APP.NEW_MENU.TOOLTIPS.CREATE_FOLDER_NOT_ALLOWED'
|
||||
) | translate
|
||||
}}">
|
||||
) | translate">
|
||||
<mat-icon>create_new_folder</mat-icon>
|
||||
<span>{{ 'APP.NEW_MENU.MENU_ITEMS.CREATE_FOLDER' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<adf-upload-button
|
||||
tooltip="{{
|
||||
(canCreateContent(node)
|
||||
[tooltip]="
|
||||
(permission.check(node, ['create'])
|
||||
? 'APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES'
|
||||
: 'APP.NEW_MENU.TOOLTIPS.UPLOAD_FILES_NOT_ALLOWED'
|
||||
) | translate }}"
|
||||
[disabled]="!canCreateContent(node)"
|
||||
) | translate"
|
||||
[disabled]="!permission.check(node, ['create'])"
|
||||
[rootFolderId]="node?.id"
|
||||
[multipleFiles]="true"
|
||||
[uploadFolders]="false"
|
||||
@@ -34,12 +47,12 @@
|
||||
</adf-upload-button>
|
||||
|
||||
<adf-upload-button
|
||||
tooltip="{{
|
||||
(canCreateContent(node)
|
||||
[tooltip]="
|
||||
(permission.check(node, ['create'])
|
||||
? 'APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS'
|
||||
: 'APP.NEW_MENU.TOOLTIPS.UPLOAD_FOLDERS_NOT_ALLOWED'
|
||||
) | translate }}"
|
||||
[disabled]="!canCreateContent(node)"
|
||||
) | translate"
|
||||
[disabled]="!permission.check(node, ['create'])"
|
||||
[rootFolderId]="node?.id"
|
||||
[multipleFiles]="true"
|
||||
[uploadFolders]="true"
|
||||
@@ -48,20 +61,33 @@
|
||||
</mat-menu>
|
||||
</div>
|
||||
|
||||
<div class="sidenav__section" *ngFor="let list of navigation">
|
||||
<div class="sidenav__section sidenav__section--menu" *ngFor="let list of navigation">
|
||||
<ul class="sidenav-menu">
|
||||
<li class="sidenav-menu__item" *ngFor="let item of list">
|
||||
<a
|
||||
class="sidenav-menu__item-link"
|
||||
[ngClass]="{ 'sidenav-menu__item-link--noicon' : !item.icon }"
|
||||
routerLinkActive="sidenav-menu__item-link--active"
|
||||
[routerLink]="item.disabled? null : item.route.url"
|
||||
[ngClass]="{ 'disabled': item.disabled }"
|
||||
title="{{ item.title || '' | translate }}">
|
||||
<mat-icon *ngIf="item.icon">{{ item.icon }}</mat-icon>
|
||||
{{ item.label | translate }}
|
||||
</a>
|
||||
<li *ngFor="let item of list" class="sidenav-menu__item"
|
||||
routerLinkActive
|
||||
#rla="routerLinkActive"
|
||||
title="{{ item.title || '' | translate }}">
|
||||
|
||||
<button [routerLink]="item.route.url"
|
||||
[color]="rla.isActive ? 'accent': 'primary'"
|
||||
mat-icon-button
|
||||
mat-ripple
|
||||
matRippleColor="primary"
|
||||
[matRippleTrigger]="rippleTrigger"
|
||||
[matRippleCentered]="true">
|
||||
|
||||
<mat-icon>{{ item.icon }}</mat-icon>
|
||||
</button>
|
||||
|
||||
<span #rippleTrigger
|
||||
class="menu__item--label"
|
||||
[routerLink]="item.route.url"
|
||||
[hidden]="!showLabel"
|
||||
[ngClass]="{
|
||||
'menu__item--active': rla.isActive,
|
||||
'menu__item--default': !rla.isActive
|
||||
}">{{ item.label | translate }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,85 +1,62 @@
|
||||
@import 'variables';
|
||||
.sidenav {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
$sidenav-section--h-padding: 24px;
|
||||
$sidenav-section--v-padding: 8px;
|
||||
&__section:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
$sidenav-menu-item--h-padding: 24px;
|
||||
$sidenav-menu-item--v-padding: 12px;
|
||||
|
||||
$sidenav-menu-item--icon-size: 24px;
|
||||
|
||||
:host {
|
||||
.sidenav {
|
||||
.section--new--mini {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__section:last-child {
|
||||
border-bottom: 0;
|
||||
&__section {
|
||||
padding: 8px 14px;
|
||||
position: relative;
|
||||
|
||||
&--new {
|
||||
padding: 16px 24px;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
&__section {
|
||||
padding:
|
||||
$sidenav-section--v-padding
|
||||
$sidenav-section--h-padding;
|
||||
|
||||
border-bottom: 1px solid $alfresco-divider-color;
|
||||
position: relative;
|
||||
|
||||
&--new {
|
||||
padding-top: 2 * $sidenav-section--v-padding;
|
||||
padding-bottom: 2 * $sidenav-section--v-padding;
|
||||
}
|
||||
|
||||
&--new__button {
|
||||
width: 100%;
|
||||
color: $alfresco-white;
|
||||
background-color: $alfresco-primary-accent--default;
|
||||
}
|
||||
&--new__button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-menu {
|
||||
margin: 0 -1 * $sidenav-section--h-padding;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
|
||||
&__item {
|
||||
padding: $sidenav-menu-item--v-padding 0;
|
||||
|
||||
&-link {
|
||||
|
||||
padding-left: $sidenav-menu-item--h-padding + 16px + 24px;
|
||||
position: relative;
|
||||
display: block;
|
||||
color: $alfresco-secondary-text-color;
|
||||
text-decoration: none;
|
||||
|
||||
& > .material-icons {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: $sidenav-menu-item--h-padding;
|
||||
margin-top: -14px;
|
||||
}
|
||||
|
||||
&--active {
|
||||
color: $alfresco-primary-accent--default;
|
||||
}
|
||||
|
||||
&:not(&--active):hover {
|
||||
color: $alfresco-primary-text-color;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: default !important;
|
||||
color: $alfresco-secondary-text-color !important;
|
||||
opacity: .25;
|
||||
}
|
||||
|
||||
&--noicon {
|
||||
padding-left: 26px;
|
||||
}
|
||||
}
|
||||
}
|
||||
&--new__button.mat-raised-button {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
&-menu {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
&-menu__item {
|
||||
padding: 12px 0;
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
text-decoration: none;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.menu__item--label {
|
||||
cursor: pointer;
|
||||
width: 240px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.menu__item--label:focus {
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,23 +27,24 @@ import { NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatMenuModule } from '@angular/material';
|
||||
import { MatMenuModule, MatSnackBarModule } from '@angular/material';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import {
|
||||
ContentService, AppConfigService, AuthenticationService,
|
||||
AppConfigService, AuthenticationService,
|
||||
UserPreferencesService, StorageService, AlfrescoApiService,
|
||||
CookieService, LogService
|
||||
CookieService, LogService, NotificationService
|
||||
} from '@alfresco/adf-core';
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
import { SidenavComponent } from './sidenav.component';
|
||||
|
||||
describe('SidenavComponent', () => {
|
||||
let fixture;
|
||||
let component: SidenavComponent;
|
||||
let contentService: ContentService;
|
||||
let browsingService: BrowsingFilesService;
|
||||
let appConfig: AppConfigService;
|
||||
let notificationService: NotificationService;
|
||||
let appConfigSpy;
|
||||
|
||||
const navItem = {
|
||||
@@ -58,6 +59,7 @@ describe('SidenavComponent', () => {
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
MatMenuModule,
|
||||
MatSnackBarModule,
|
||||
TranslateModule.forRoot(),
|
||||
RouterTestingModule
|
||||
],
|
||||
@@ -71,17 +73,18 @@ describe('SidenavComponent', () => {
|
||||
StorageService,
|
||||
UserPreferencesService,
|
||||
AuthenticationService,
|
||||
ContentService,
|
||||
NodePermissionService,
|
||||
AppConfigService,
|
||||
BrowsingFilesService
|
||||
BrowsingFilesService,
|
||||
NotificationService
|
||||
],
|
||||
schemas: [ NO_ERRORS_SCHEMA ]
|
||||
})
|
||||
.compileComponents()
|
||||
.then(() => {
|
||||
contentService = TestBed.get(ContentService);
|
||||
browsingService = TestBed.get(BrowsingFilesService);
|
||||
appConfig = TestBed.get(AppConfigService);
|
||||
notificationService = TestBed.get(NotificationService);
|
||||
|
||||
fixture = TestBed.createComponent(SidenavComponent);
|
||||
component = fixture.componentInstance;
|
||||
@@ -99,32 +102,6 @@ describe('SidenavComponent', () => {
|
||||
expect(component.node).toBe(node);
|
||||
});
|
||||
|
||||
it('should have permission to create content', () => {
|
||||
fixture.detectChanges();
|
||||
spyOn(contentService, 'hasPermission').and.returnValue(true);
|
||||
const node: any = {};
|
||||
|
||||
expect(component.canCreateContent(node)).toBe(true);
|
||||
expect(contentService.hasPermission).toHaveBeenCalledWith(node, 'create');
|
||||
});
|
||||
|
||||
it('should not have permission to create content for missing node', () => {
|
||||
fixture.detectChanges();
|
||||
spyOn(contentService, 'hasPermission').and.returnValue(true);
|
||||
|
||||
expect(component.canCreateContent(null)).toBe(false);
|
||||
expect(contentService.hasPermission).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not have permission to create content based on node permission', () => {
|
||||
fixture.detectChanges();
|
||||
spyOn(contentService, 'hasPermission').and.returnValue(false);
|
||||
const node: any = {};
|
||||
|
||||
expect(component.canCreateContent(node)).toBe(false);
|
||||
expect(contentService.hasPermission).toHaveBeenCalledWith(node, 'create');
|
||||
});
|
||||
|
||||
describe('menu', () => {
|
||||
it('should build menu from array', () => {
|
||||
appConfigSpy.and.returnValue([navItem, navItem]);
|
||||
@@ -140,4 +117,16 @@ describe('SidenavComponent', () => {
|
||||
expect(component.navigation).toEqual([[navItem, navItem], [navItem, navItem]]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('openSnackMessage', () => {
|
||||
it('should call notification service', () => {
|
||||
const message = 'notification message';
|
||||
|
||||
spyOn(notificationService, 'openSnackMessage');
|
||||
|
||||
component.openSnackMessage(message);
|
||||
|
||||
expect(notificationService.openSnackMessage).toHaveBeenCalledWith(message, 4000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
@mixin sidenav-component-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$foreground: map-get($theme, foreground);
|
||||
$background: map-get($theme, background);
|
||||
|
||||
$border: 1px solid mat-color($foreground, divider, .07);
|
||||
|
||||
.sidenav {
|
||||
@include angular-material-theme($theme);
|
||||
|
||||
background-color: mat-color($background, background);
|
||||
border-right: $border;
|
||||
|
||||
&__section {
|
||||
border-bottom: $border;
|
||||
}
|
||||
|
||||
.menu__item--label:not(.menu__item--active):hover {
|
||||
color: mat-color($foreground, text);
|
||||
}
|
||||
|
||||
.menu__item--active {
|
||||
color: mat-color($accent);
|
||||
}
|
||||
|
||||
.menu__item--default {
|
||||
color: mat-color($primary, .87);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -24,13 +24,13 @@
|
||||
*/
|
||||
|
||||
import { Subscription } from 'rxjs/Rx';
|
||||
|
||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||
|
||||
import { Component, Input, OnInit, OnDestroy } from '@angular/core';
|
||||
import { MinimalNodeEntryEntity } from 'alfresco-js-api';
|
||||
import { ContentService, AppConfigService } from '@alfresco/adf-core';
|
||||
import { AppConfigService, NotificationService } from '@alfresco/adf-core';
|
||||
|
||||
|
||||
import { BrowsingFilesService } from '../../common/services/browsing-files.service';
|
||||
import { NodePermissionService } from '../../common/services/node-permission.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-sidenav',
|
||||
@@ -38,15 +38,18 @@ import { BrowsingFilesService } from '../../common/services/browsing-files.servi
|
||||
styleUrls: ['./sidenav.component.scss']
|
||||
})
|
||||
export class SidenavComponent implements OnInit, OnDestroy {
|
||||
@Input() showLabel: boolean;
|
||||
|
||||
node: MinimalNodeEntryEntity = null;
|
||||
navigation = [];
|
||||
|
||||
private subscriptions: Subscription[] = [];
|
||||
|
||||
constructor(
|
||||
private notificationService: NotificationService,
|
||||
private browsingFilesService: BrowsingFilesService,
|
||||
private contentService: ContentService,
|
||||
private appConfig: AppConfigService
|
||||
private appConfig: AppConfigService,
|
||||
public permission: NodePermissionService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -58,15 +61,15 @@ export class SidenavComponent implements OnInit, OnDestroy {
|
||||
]);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach(s => s.unsubscribe());
|
||||
openSnackMessage(event: any) {
|
||||
this.notificationService.openSnackMessage(
|
||||
event,
|
||||
4000
|
||||
);
|
||||
}
|
||||
|
||||
canCreateContent(parentNode: MinimalNodeEntryEntity): boolean {
|
||||
if (parentNode) {
|
||||
return this.contentService.hasPermission(parentNode, 'create');
|
||||
}
|
||||
return false;
|
||||
ngOnDestroy() {
|
||||
this.subscriptions.forEach(s => s.unsubscribe());
|
||||
}
|
||||
|
||||
private buildMenu() {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
<adf-toolbar class="inline">
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
[app-permanent-delete-node]="documentList.selection"
|
||||
(selection-node-deleted)="refresh()"
|
||||
@@ -14,6 +15,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
color="primary"
|
||||
mat-icon-button
|
||||
(selection-node-restored)="refresh()"
|
||||
[app-restore-node]="documentList.selection"
|
||||
@@ -25,80 +27,84 @@
|
||||
</div>
|
||||
|
||||
<div class="inner-layout__content">
|
||||
<div class="inner-layout__panel" [ngClass]="{'adf-document-list--loading': documentList.isEmpty()}">
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'adf-document-list--empty' : ''"
|
||||
currentFolderId="-trashcan-"
|
||||
selectionMode="multiple"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)">
|
||||
|
||||
<adf-document-list #documentList
|
||||
[attr.class]="documentList.isEmpty() ? 'empty-list' : ''"
|
||||
currentFolderId="-trashcan-"
|
||||
selectionMode="multiple"
|
||||
[navigate]="false"
|
||||
[sorting]="sorting"
|
||||
[contextMenuActions]="true"
|
||||
[contentActions]="false"
|
||||
(sorting-changed)="onSortingChanged($event)">
|
||||
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="delete"
|
||||
title="APP.BROWSE.TRASHCAN.EMPTY_STATE.TITLE">
|
||||
<p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.FIRST_TEXT' | translate }}</p>
|
||||
<p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.SECOND_TEXT' | translate }}</p>
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-columns>
|
||||
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
<empty-folder-content>
|
||||
<ng-template>
|
||||
<app-empty-folder
|
||||
icon="delete"
|
||||
title="APP.BROWSE.TRASHCAN.EMPTY_STATE.TITLE">
|
||||
<p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.FIRST_TEXT' | translate }}</p>
|
||||
<p class="app-empty-folder__text">{{ 'APP.BROWSE.TRASHCAN.EMPTY_STATE.SECOND_TEXT' | translate }}</p>
|
||||
</app-empty-folder>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
</empty-folder-content>
|
||||
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-columns>
|
||||
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
|
||||
type="fileSize">
|
||||
</data-column>
|
||||
<data-column
|
||||
key="$thumbnail"
|
||||
type="image"
|
||||
[sortable]="false"
|
||||
class="image-table-cell">
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
key="archivedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.DELETED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis__name"
|
||||
key="name"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.NAME">
|
||||
<ng-template let-value="value" let-context>
|
||||
<span class="adf-datatable-cell" title="{{ context?.row?.obj | adfNodeNameTooltip }}">{{ value }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="archivedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.DELETED_BY">
|
||||
</data-column>
|
||||
<data-column
|
||||
key="path"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.LOCATION">
|
||||
<ng-template let-context>
|
||||
<app-location-link [context]="context"></app-location-link>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
</data-columns>
|
||||
<data-column
|
||||
key="content.sizeInBytes"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.SIZE"
|
||||
type="fileSize">
|
||||
</data-column>
|
||||
|
||||
</adf-document-list>
|
||||
<adf-pagination [ngClass]="{ 'no-border' : documentList.isEmpty()}"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
<data-column
|
||||
key="archivedAt"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.DELETED_ON">
|
||||
<ng-template let-value="value">
|
||||
<span title="{{ value | date:'medium' }}">{{ value | adfTimeAgo }}</span>
|
||||
</ng-template>
|
||||
</data-column>
|
||||
|
||||
<data-column
|
||||
class="adf-data-table-cell--ellipsis"
|
||||
key="archivedByUser.displayName"
|
||||
title="APP.DOCUMENT_LIST.COLUMNS.DELETED_BY">
|
||||
</data-column>
|
||||
|
||||
</data-columns>
|
||||
</adf-document-list>
|
||||
|
||||
<ng-container *ngIf="!documentList.isEmpty()">
|
||||
<adf-pagination
|
||||
[supportedPageSizes]="'pagination.supportedPageSizes' | appConfig"
|
||||
[target]="documentList"
|
||||
(changePageSize)="onChangePageSize($event)">
|
||||
</adf-pagination>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user