Compare commits

..
153 Commits
Author SHA1 Message Date
Popovics András edaec010e6 MDL tooltip not displayed bugfix (#2025) 2017-07-03 15:49:52 +02:00
Vito d0271bc188 [ADF - 334] Added prefix to amount widget (#2031)
[ADF - 334] added material design prefix to amount widget
2017-07-03 09:18:11 +01:00
Vito fa0e416851 [ADF - 950] - disabling date button on readonly form (#2032) 2017-06-30 22:25:03 +01:00
Denys Vuika c3f60e5a3b AOT compatibility enhancements (#2015)
* aot compatibility updates

- remove index files where needed
- move material dependencies to a separete module
- use aot compatible lambda functions for module export

* remove unused imports

* re-export Material module

* core module enhancements

- fix AOT issue with providers (use lambda instead of variable)
- move context menu to a separate module

* core module enhancements

* feature modules
2017-06-30 22:20:12 +01:00
Eugenio Romano 151ea88cd0 no save development js-api (#2033) 2017-06-30 17:38:01 +01:00
Jean-Pierre Huynh 49dfe721fc Fix markdown syntax and wording on README.md (#2030) 2017-06-30 16:42:44 +01:00
Eugenio Romano ffbcd7aa48 regenerate lock 2017-06-30 01:21:09 +01:00
Eugenio Romano 6abf87994c bump version 1.6.0 (#2027) 2017-06-29 15:09:30 +01:00
Eugenio Romano 0317cb4e3b fix search miss typing 2017-06-29 15:09:30 +01:00
Maurizio Vitale 78bf96481e Add screenshot (#2028) 2017-06-29 15:09:30 +01:00
Eugenio Romano aa4864a496 fix tslint error in tasklist 2017-06-29 15:09:30 +01:00
Eugenio Romano 2416107457 NgZone type passed parameter 2017-06-29 15:09:29 +01:00
Eugenio Romano 33ef6ff6d5 fix type definition variables 2017-06-29 15:09:29 +01:00
Eugenio Romano 829eac2dcf update viewer readme 2017-06-29 15:09:29 +01:00
Eugenio Romano 56f59ffd58 update typescript (#2026) 2017-06-29 15:09:29 +01:00
Maurizio Vitale 0a0884c2a8 Fix upload process attachment (#2024) 2017-06-29 15:09:29 +01:00
Eugenio Romano 9fb93c5f30 regeneration TOC and add automatic list component generator (#2022) 2017-06-29 15:09:28 +01:00
Vito a431f3934f [ADF-907] - Form reacts to data added in input (#2016)
* [ADF-907] Enable activiti form to react on value data changes

* [ADF-907] - Form reacts to data added in input]

* [ADF - 907] added mock json for form

* [ADF-907] added new event of the form to the event list

* [ADF - 907] Added return column to README

* [ADF - 907] Added return column to README
2017-06-29 15:09:28 +01:00
Maurizio Vitale e30a1aed30 Fix upload related content (#2019) 2017-06-29 15:09:28 +01:00
Eugenio Romano 2768b68168 install globally pkg pre build 2017-06-29 15:09:28 +01:00
Eugenio Romano 00416f76d7 Script add pkg and clean update 2017-06-29 15:09:28 +01:00
Eugenio Romano 1b259ebef2 Fix readme document list 2017-06-29 15:09:27 +01:00
Eugenio Romano 82cad3415b create new TaskDetailsModel in loadNextTask (#2017) 2017-06-29 15:09:27 +01:00
Eugenio Romano f6116bf937 Appveyor test (#1998)
* reduce memory

* remove max-old-space

* remove increase memory
2017-06-29 15:09:27 +01:00
Eugenio Romano abf39b6f41 move appveyor to node 8 2017-06-29 15:09:27 +01:00
Eugenio Romano 24b1e0fe51 fix clean scripts demo folders 2017-06-29 15:09:27 +01:00
Eugenio Romano 5e7e43f18a install rimraf globally 2017-06-29 15:09:26 +01:00
Eugenio Romano 628f5f13ca modify prePublish script with preoPublishOnly 2017-06-29 15:09:26 +01:00
Eugenio Romano ce1403612a prepublish script deprecation in favour of prepublishOnly node 8 (#2010) 2017-06-29 15:09:26 +01:00
Eugenio Romano a6099ae4a1 vjsapi option prepublish 2017-06-29 15:09:26 +01:00
Eugenio Romano 49dd57df9f SASS version update (#2013)
* sass update

* update sass loader
2017-06-29 15:09:25 +01:00
Popovics András ba9c459a83 [ADF-922] Regenerate package-lock.json files for every package and create script for doing that in the future (#2012)
* Updated package-lock.json files

* npm-relock-pkgs.sh

* Update README.md

* Fix ng2-alfresco-search sass problem
2017-06-29 15:09:25 +01:00
Eugenio Romano 6f6a0aca5d fix breadcrumb test 2017-06-29 15:09:25 +01:00
Denys Vuika 0a7c8c99be fix tslint errors 2017-06-29 15:09:24 +01:00
Maurizio Vitale 449e99d071 Missing keys (#2011) 2017-06-29 15:09:24 +01:00
Eugenio Romano 7fd37c553e [ADF-845] breadcrumb root option added and style review (#1999)
* breadcrumb root option added and style review

* new breadcrumbs

* split onchange in a method

* update readme with a note for old pefix tag
2017-06-29 15:09:24 +01:00
Eugenio Romano fa75eb03b3 [ADF-915] Add option to change the JS-API with different version in the update package 2017-06-29 15:09:24 +01:00
Eugenio Romano f66178d601 [ADF-843] Form events bus (#1990)
* form events bus

* event test bus fix

* fix test after code review

* fix types errors

* change to public formservice

* make optional formservice
2017-06-29 15:09:24 +01:00
Eugenio Romano d5ee1e8baa add rxjs and @angular in tsconfig.json 2017-06-29 15:09:23 +01:00
Vito d61ed8087d [ADF-842] Fixed type for taskdetails (#2009) 2017-06-29 15:09:23 +01:00
Maurizio Vitale 88114952c2 Use the activiti people with the new look and feel inside the demo shell (#2008) 2017-06-29 15:09:23 +01:00
Eugenio Romano beba80d8e8 fix type definition (#2002) 2017-06-29 15:09:23 +01:00
Denys Vuika 56179c2e88 fix tslint errors
minor fix for "Unnecessary semicolon" TSLint rule
2017-06-29 15:09:22 +01:00
Vito ef340a398e [ADF-778] cancel window for upload dialog shows only on complete (#2003)
* [ADF-778] Added new behaviour to upload dialog

* [ADF-778] cancel window for upload dialog shows only on complete

* [ADF-778] changed variable name to showCloseButton
2017-06-29 15:09:22 +01:00
Maurizio Vitale bffaf2c407 Create task/process attachment Compilation error (#2004) 2017-06-29 15:09:22 +01:00
Denys Vuika 036f131122 support binding [form] data directly (#1996)
- ability to bind [form] data directly inside `<activiti-form>` component
- ability to parse forms with FormService
- demo of the custom form in demo shell
2017-06-29 15:09:22 +01:00
Maurizio Vitale 5e3f14963b [ADF-897] - ActivitiPeopleList - use the adf prefix (#2001)
* Use the adf as prexif instead of activiti

* Fix typo

* Fix wrong import
2017-06-29 15:09:22 +01:00
Eugenio Romano 62df024e48 introduce check type definition 2017-06-29 15:09:22 +01:00
mauriziovitale84 9c3c5d9dc7 Fix typo error 2017-06-29 15:09:21 +01:00
Infad Kachancheri 5f0e328063 [ADF-794] Add people assignment component (#1977)
* Add people component

* exported people service

* added people-list component to show the involved user list

* changed people-search component layout

* changed people-list usage in people component

* changed people-list data table from custom template to data adapter

* changes people-search component related to people-list

* changes in activiti-people related to people-list and people-search component

* changed data adapter to direct data column setting to data-table

* removed ngChanges and added User and UserEvent models

* added User and UserEvent model in emitter and other emitter handler

* added user event model

* changed activiti-people component with latest UX changes

* addedand changed translate keys to the components

* added hasUser method to check the condition in html

* fixed tslint issue and test case issue in activiti-people component

* added test case for actviti-people-list component

* test case added for activiti-people-search component

* changed activiti-people test cases according to latest UX changes

* added description for activiti-people component

* changed test case to fix component.upgradeElement issue

* changes requested by Vito Albano #1

* splitted getDisplayUser into getDisplayUser and getInitialUsername
2017-06-29 15:09:21 +01:00
Denys Vuika 3e8d952ad4 remove flags lib from demo shell (#1983)
* remove flags lib from demo shell

greatly reduce demo shell webpack resources by switching off flags (only 3 icons were displayed in the past)

* merge package.json

* add icons
2017-06-29 15:09:21 +01:00
dmonteiro-alfresco a3dfa155f2 [ADF-822] Added the npm-prepublish script (#1978)
* added the npm prepublish script

* changed permissions to prepublish script

* changed to npm run prepublish

* prepare the pr

* removed useless code to the script
2017-06-29 15:09:21 +01:00
Denys Vuika 38dfa17e3f app settings page (#1997)
- custom app setttings service to use isolated storage (demo shell)
- restore settings UI
- redirect angular and rxjs to the same version as components use.
2017-06-29 15:09:21 +01:00
Popovics András b457024cab [ADF-793] Ability to create PDF renditions in case of non supported formats (#1994)
* Style changes and button

* Convert to PDF button

* Convert to PDF button part II.

* Convert within the Not Supported Format component

* Rendition loading skeleton

* Conversion is working.

* Convert button behaviour tests

* Rebasing fix.
2017-06-29 15:09:20 +01:00
Maurizio Vitale 0ff4ff5f24 [ADF-883] Fix build errors (#1992) 2017-06-29 15:09:20 +01:00
Maurizio Vitale cb5d0e8886 Fix compilation error (#1993) 2017-06-29 15:09:20 +01:00
Eugenio Romano 0669575cb8 fix loading state excluding other state during the loading (#1991) 2017-06-29 15:09:20 +01:00
Denys Vuika 201741aeee [ADF-851] execute-outcome event for form service (#1989)
* execute-outcome event for form service

* readme updates
2017-06-29 15:09:20 +01:00
Denys Vuika b7ab008081 updated package-lock file and removed duplicates in package.json 2017-06-29 15:09:20 +01:00
Denys Vuika d5f64fa9fc [ADF-847] upgrade to use application configuration service (#1986)
* migrate core lib to use server-side app config

* fix unit tests

* update Search tests

- update tests
- upgrade tests to use TestBed

* update UserInfo tests

* update Social tests

* update tests

* update unit tests

* cleanup old code

* update about page

* update demo shell readme

* dev and prod configurations
2017-06-29 15:09:19 +01:00
Maurizio Vitale f5b94e1bb4 Disable upload attachment when the task is completed (#1987) 2017-06-29 15:09:19 +01:00
Maurizio Vitale 4de13305b1 Task header basic documentation (#1985) 2017-06-29 15:09:19 +01:00
Maurizio Vitale 4e7c5bfdbf [ADF-833] DataTable - improve the single and double click event (#1979)
* Improve the single and double click event

* Fix unit test
2017-06-29 15:09:19 +01:00
Denys Vuika 3ca7503ddb add missing intl dependency for demo shell (#1984) 2017-06-29 15:09:19 +01:00
Eugenio Romano 27f497c219 Table of content automatic creation (#1982) 2017-06-29 15:09:18 +01:00
Eugenio Romano 44161dc4d5 readonly value set 2017-06-29 15:09:18 +01:00
Eugenio Romano 8e30af9d46 [ADF-838] Table of content automatic creation (#1981) 2017-06-29 15:09:18 +01:00
Eugenio Romano 99467ba957 [ADF-524] Fix empty state after the loading introduction (#1980)
* fix empty state after the loading introduction

* Update document-list.component.spec.ts

remove typo
2017-06-29 15:09:18 +01:00
Denys Vuika 0a81979a4d [ADF-717] upgrade i18n and charting dependencies (#1976)
* remove app-specific polyfill dependencies

remove polyfill dependencies never used by component libraries

* upgrade i18n dependencies

* upgrade ng2-charts dependency

* fix unit tests

* update demo projects
2017-06-29 15:09:18 +01:00
Vito 45f14fa506 [ADF-510] Drag&Drop check permission to allow user to upload a file (#1948)
* [ADF-510] added permission check for drag&drop

* Improved code for drag and drop side

* Added test for drag and drop upload area changes

* Added test for document list permissions check

* [ADF-510] rebased branch after changes applied to upload

* [ADF-510] rebased branch and fixed tests
2017-06-29 15:09:18 +01:00
Eugenio Romano 25cefc6414 [ADF-810] fix default value radio button (#1975) 2017-06-29 15:09:17 +01:00
Denys Vuika 142d6a0bbf fix issue with shared Code settings
- remove obsolete rules for .js/.ts
- hide .happypack folder in the project tree
2017-06-29 15:09:17 +01:00
Maurizio Vitale d787160c26 [ADF-716] Task Header - Use a custom view inside the component (#1967)
* Use a generic custom view inside the task header

* Move the component into core component and change name

* Missing file

* Fix unit test

* fix unit test component name
2017-06-29 15:09:17 +01:00
Denys Vuika 6393ecbff5 [ADF-814] application configuration service (#1969)
* app configuration service

* api improvements and readme update

* extend readme and add defaults

* unit tests for app config service
2017-06-29 15:09:17 +01:00
Vito b045044d12 [ADF-494] fixed readonly rendering for forms (#1972)
* [ADF-494] improved disabling for form

* [ADF-494] fixed readonly rendering for forms
2017-06-29 15:09:17 +01:00
Eugenio Romano 590a7eb650 remove brachet 2017-06-29 15:09:16 +01:00
Eugenio Romano 3cfe8b1b6f Fix host configuration in demo-shell when no port is present (#1971) 2017-06-29 15:09:16 +01:00
Eugenio Romano 72a01918ee [ADF-78] Update CORS help (#1973) 2017-06-29 15:09:16 +01:00
Eugenio Romano f3d5b88671 [ADF-524] Datatable loading state (#1958)
* loading state datatable

* modify readme after review
2017-06-29 15:09:16 +01:00
Popovics András 069345a028 Fix current page number issue (#1970) 2017-06-29 15:09:16 +01:00
Eugenio Romano 8462c3da1f karma conf all single browser 2017-06-29 15:09:16 +01:00
Popovics András b79f9c58f6 Adding tabindices to viewer control elements (#1968) 2017-06-29 15:09:15 +01:00
Popovics András fb4af7f846 [ADF-578] Remember me functionality (#1962)
* Remember me functionality

* Happy pack to ng2-components' package.json

* Build fix
2017-06-29 15:09:15 +01:00
Denys Vuika 75778ab968 fix builds related to node-sass library (#1966)
* update dependencies and remove old lock files

* update sass loader

* updated lock files
2017-06-29 15:09:15 +01:00
Denys Vuika 774498e045 [ADF-591] documentation refinements (#1959)
* refine ng2-activiti-analytics

* refine ng2-activiti-diagrams docs

* refine ng2-activiti-form

* refine ng2-activiti-processlist

* refine ng2-activiti-tasklist

* refine ng2-alfresco-core

* refine ng2-alfresco-datatable

* refine ng2-alfresco-datatable

* refine gn2-alfresco-login

* refine ng2-alfresco-search

* refine ng2-alfresco-social

* refine ng2-alfresco-tag

* refine ng2-alfresco-upload

* refine ng2-alfresco-userinfo

* refine ng2-alfresco-viewer

* refine ng2-alfresco-webscript

* various readme cleanups
2017-06-29 15:09:15 +01:00
Denys Vuika b21c4e3dca upload service exposes created nodes (#1964) 2017-06-29 15:09:15 +01:00
Denys Vuika 85b528f5d3 update travis to node 8 (#1965) 2017-06-29 15:09:14 +01:00
Eugenio Romano 4643b68345 package lock update 2017-06-29 15:09:14 +01:00
Eugenio Romano b6bf53f457 [ADF-804] webpack proxy setup to avoid CORS problem (#1960) 2017-06-29 15:09:14 +01:00
Eugenio Romano 5699b45f1d [ADF-797] remove dist folder from npm distributed package , leave src and bundles (#1961) 2017-06-29 15:09:14 +01:00
Vito c94ca2cb4c [ADF-802] fix error on uploading file to attachment list (#1957)
* [ADF-802] fix error on uploading file to attachment list

* [ADF-802] improved for loop
2017-06-29 15:09:14 +01:00
Vito ab57b6fcd1 [ADF-740] Add button for process attachment list (#1955)
* [ADF-740] adding button to allow user to upload related content on process instance

* [ADF-740] add button for attachment content list for process

* changed locatin for translation

* [ADF-740] added test for add button for process attach

* [ADF-740] added PR request changes
2017-06-29 15:09:14 +01:00
Denys Vuika acd65d59e7 update npm5 lock files 2017-06-29 15:09:13 +01:00
Eugenio Romano ccfb63b536 [ADF-799] add HappyPack to webpack conf (#1956) 2017-06-29 15:09:13 +01:00
Denys Vuika 038a06d055 fix issues with the require keyword (angular cli) (#1954) 2017-06-29 15:09:13 +01:00
Popovics András c0ca744d17 [ADF-589] Login component different bug fixes (#1953)
* Basic style changes

* Further design changes

* Responsive design fixes

* Different sign in button style for the different login steps
2017-06-29 15:09:13 +01:00
Deepak Paul 969658891d #ADF-780 Fixed getProcessFilterByName to get the correct filter for the given appId and name (#1952) 2017-06-29 15:09:13 +01:00
Denys Vuika a02ba4ad71 [ADF-643] upload enhancements (#1949)
* rework folder uploading

- flatterns hierarchy on folder upload
- performs a single traversal for the entire folder heirarchy and ends with a comple file list
- allows now dropping folders on existing folders
- overall code improvements

* fix unit tests

* readme updates

* clean old and unused code

* code cleanup

* limit concurrent uploads

* update code as per review

* fix upload button for Safari

* fixes for Safari

- Safari compatibility
- code updates based on review

* fix code

* fix unit tests
2017-06-29 15:09:12 +01:00
Eugenio Romano e7a1f46ac8 fix thumbnail task process list (#1951) 2017-06-29 15:09:12 +01:00
Vito f60035369a [ADF-780] centralised call for process filters api (#1950)
* [ADF-780] centralised call for process filters api

* [ADF-780] updated conversion to string
2017-06-29 15:09:12 +01:00
Maurizio Vitale 33d5f66bd7 [ADF-741] Add the create task attachment component to the demo shell (#1946)
* Add the create task attachment component to the demo shell

* Add translation keys

* Add return to methods
2017-06-29 15:09:12 +01:00
Maurizio Vitale cfb3c9b8ba [ADF-773] Fix datatable custom template render (#1947) 2017-06-29 15:09:12 +01:00
Eugenio Romano ae683ad708 fix translation wrong folder creation issue 2017-06-29 15:09:11 +01:00
Popovics András 2c46f265e3 [ADF-689] Fix alfresco-document-menu-action styling (z-index) (#1944) 2017-06-29 15:09:11 +01:00
Popovics András 519335294b GitHub issue & pull request template change (#1945)
* Update ISSUE_TEMPLATE.md

* Update PULL_REQUEST_TEMPLATE.md
2017-06-29 15:09:11 +01:00
Eugenio Romano c6bfe892ee fix blob input in text viewer (#1942) 2017-06-29 15:09:11 +01:00
Popovics András d3eee53ee4 Adding new icon (sent) for Bootstrap to Material icon mapping (#1943) 2017-06-29 15:09:11 +01:00
Popovics András 8c68fbb50e [ADF-763] Add Chrome default browser for karma chrome launcher for Chrome versi… (#1941)
* Add Chrome default browser for karma chrome launcher for Chrome version<59

* Fixing intermittently failing test in ng2-activiti-analytics component
2017-06-29 15:09:11 +01:00
Denys Vuika 6aa6a155e2 [ADF-754] toolbar component (#1938)
* toolbar component

- simple toolbar component (core lib)
- readme updates (core lib)
- update demo shell with toolbar component demo (document list)

* update unit tests
2017-06-29 15:09:10 +01:00
Eugenio Romano 6258aa3dd0 add info and link on current last git commit (#1940) 2017-06-29 15:09:10 +01:00
Denys Vuika 0599f1a441 support for healdess chrome (#1939) 2017-06-29 15:09:10 +01:00
Maurizio Vitale 7289315c37 [ADF-744] Attachment List is not displayed within Processes. (#1937)
* Use the adf process attachment list indise demo shell

* Change documentation
2017-06-29 15:09:10 +01:00
Maurizio Vitale c278fd9910 [ADF-702] Task/Process Filter - Provide a way to change the default filter (#1932)
* [ADF-702] Task/Process Filter - Provide a way to change the default filter

* Provide a way to select a custom menu filter

* Improve activiti process filter

* Add internal link

* Change link name

* add link
2017-06-29 15:09:10 +01:00
Deepak Paul 8b7b57efe6 #ADF-696 Now accordion opens/closes on click of group header along with emitting heading click event (#1936) 2017-06-29 15:09:10 +01:00
Eugenio Romano eae9064213 coverage fix (#1934) 2017-06-29 15:09:09 +01:00
Maurizio Vitale 23fbc8f858 [ADF-686] add blobFile as input (#1933) 2017-06-29 15:09:09 +01:00
Eugenio Romano 033c0f0a6b fix pacakge.json tag 2017-06-29 15:09:09 +01:00
Eugenio Romano a3e1b3680f rollback demo tag 2017-06-29 15:09:09 +01:00
Eugenio Romano bb250543bc add sleep time flag in publish script 2017-06-29 15:09:09 +01:00
Denys Vuika 4b7c958992 remove old 'banned' demo from login screen (#1929) 2017-06-29 15:09:08 +01:00
Eugenio Romano 1060b66534 move coverage separate file and get component to calculate coverage as input 2017-06-29 15:09:08 +01:00
Eugenio Romano 282e64f93d Source Mapping is not working on test debugging (#1931)
* coverage single components run fix

* remove spec.ts from coverage

* make the coverage and the istanbul-instrumenter-loader works only over the console test because a problem on the remapping for the browser test

* move tslint on the main folder of any component

* remove build:w from readme

* stop build tslint error also in spec files

* clear karma file from unnecessary files

* add set -f for build all script in order to accept *

* fix lint problem and failing tests

* fix failing test search component

* add loader test for viewer

* fix tslint error userinfo

* --max_old_space_size=2048 remove

* fix tslint error uploader unused EventEmitter

* remove spec|index|.*mock|.*model|.*event from coverage
2017-06-29 15:09:08 +01:00
Denys Vuika ed30b74ce6 lock files for npm 5 (#1930)
add lock files for npm v5; does nothing for earlier versions, so is not harmful
2017-06-29 15:09:08 +01:00
Denys Vuika 3b3b8b4fa8 fix file upload bug (#1928)
- proper extraction of File objects from the FileList
2017-06-29 15:09:08 +01:00
Vito 0c995bff6e [ADF-709] add autofocus when a new row is added on dynamic table widget (#1927)
* [ADF-709] add autofocus when a new row is added on dynamic table widget

* [ADF-709] removed wrong reference for template
2017-06-29 15:09:07 +01:00
Denys Vuika cc7b205f54 fix i18n issue with webpack 2017-06-29 15:09:07 +01:00
Denys Vuika c2fee79724 [ADF-571] upload feature rework (#1922)
* upload feature rework

lots of improvements for upload dialog and underlying services

* readme update

- readme cleanup
- remove some old comments from code
- update readme with new events for Upload Service

* restore prerequisites section in readme
2017-06-29 15:09:07 +01:00
Hussain Ashraf b4c9710e71 Add data-automation-id to multi select checkbox (#1924) 2017-06-29 15:09:07 +01:00
Infad Kachancheri 87314b5a0d exported report and chart models (#1925) 2017-06-29 15:09:07 +01:00
Infad Kachancheri 52d2d7a349 [ADF-713] Process Attachment - Provide a way to attach a new content (#1920)
* added service to get all the related content of the process instance

* added new component to create/upload attachment for process instance

* added unit test cases for create-process-attachment component

* exported create-process-attachment component

* added documentation for create-process-attachment component
2017-06-29 15:09:07 +01:00
Eugenio Romano 9db047f8fc [ADF-721] Fix translation reference for dev task (#1923)
* move translation files in the bundles folder

* fix after review
ripristinate tslint and remove override tsconfig
2017-06-29 15:09:06 +01:00
Vito 7572c8d098 [ADF-707] Ability to select a row on a dynamic table (#1921) 2017-06-29 15:09:06 +01:00
Deepak Paul 2f79163451 [ADF-696] Entire accordion group header should be clickable (#1918)
* #ADF-696 Added new input to show/hide expand icon, click event is activated for the complete heading

* #ADF-696 tslint fix

* #ADF-696 Added documentation for new input and removed unwanted div
2017-06-29 15:09:06 +01:00
Infad Kachancheri 8afe6e2125 [ADF-712] Task Attachment - Provide a way to attach a new content (#1898)
* create button, download, view functionality added in task attachment list component

* created sevice to attach document to task

* added new component to create/uplaod attachment to task

* added new component to create/uplaod attachment to task

* added test case for create task attachment component

* added test case for create task attachment component

* added input to block upload document  to ECM

* fixed create task attachment spec file issue

* changed alfresco-upload to alfresco-core upload directive

* removed attachCreate button and emitter from task-attachment-list

* removed uploadToEcm input and checkValidity method from alfresco-upload

* added documentation for task-attachment-list and create-task-attachment components
2017-06-29 15:09:06 +01:00
Infad Kachancheri c445b6a4df [ADF-710] Create an Process Attachment List component (#1919)
* added new component to list the process attachments with view, download and delete functionality

* added unit test cases for activit-process-attachment-list component

* exported new process attachment list component

* added documentation for process-attachment-list component
2017-06-29 15:09:06 +01:00
Maurizio Vitale 9b7588cf11 ADF-402 add the show diagram button (#1917) 2017-06-29 15:09:05 +01:00
Eugenio Romano c57f6450f0 add option only demo shell version change for update version script 2017-06-29 15:09:05 +01:00
Eugenio Romano b59fd4036d wav and Mp3 enabling viewer (#1916) 2017-06-29 15:09:05 +01:00
Eugenio Romano 90a7b282ab move demo projects to webpack (#1915) 2017-06-29 15:09:05 +01:00
Denys Vuika 5025303980 [ADF-667] selection mode and row styles (#1914)
* selection mode and row styles

- single/multiple/none selection modes for DataTable component (and Document List)
- support for custom row styles (inline and classname values)
- fix karma config (material themes)
- readme updates
- package-lock.json files for NPM5 support
- updated DataTable demo to demonstrate selection modes and row styles

* remove package lock files
2017-06-29 15:09:05 +01:00
Vito 950a987a6c [ADF-680] Added previous page check when page has no more elements (#1911)
* [ADF-242] - fix for deleting - saving a report

* [ADF - 242] added test for fixed feature on reports save - delete

* [ADF-680] - Fixed behaviour when deleting all files on last page of document list

* Start adding test for documentlist check

* Added test for check double page load

* [ADF-680] - removed commented test code

* [ADF-680] Added changes from peer review

* [ADF-680] added return type
2017-06-29 15:09:04 +01:00
Maurizio Vitale 265d484788 [ADF-602] Accordion component - Add basic documentation (#1913)
* Add basic documentation Accordion component

* Update README.md
2017-06-29 15:09:04 +01:00
Denys Vuika 1ffc3cd080 [ADF-573] support for toggling enabled state (#1912) 2017-06-29 15:09:04 +01:00
Eugenio Romano 4b5eb4bb29 [ADF-613] Add plain text viewer (#1873)
* add plain text viewer

* different devices optimizations

* returns types
2017-06-29 15:09:04 +01:00
Denys Vuika a2ef939860 [ADF-604] Upgrade @angular/material to latest version (#1909)
* update dependencies and module imports

* fix template warnings and fix import issues

* migrate Activiti Form to MdTabsModule

* fix unit tests

* fix tests

* fix unit tests

* fix unit tests

* disable test that fails only on travis

* upgrade activiti form component to angular/material

* fix test (remove MDL class check)
2017-06-29 15:09:04 +01:00
Vito 6e3e3ab5b7 [ADF-242] Fixed behaviour for saving/deleting reports (#1905)
* [ADF-242] - fix for deleting - saving a report

* [ADF - 242] added test for fixed feature on reports save - delete

* Added translation key
2017-06-29 15:09:04 +01:00
Denys Vuika 7b17b10ef1 [ADF-621] show drop effect on folders only (#1897)
* show drop effect on folders only

- fix `hasValue` api for data rows (avoid 'false' value to be evaluated as missing value)
- support for evaluating drop support for rows
- document list enables upload zones for folders only

* api improvements as per code review
2017-06-29 15:09:03 +01:00
Denys Vuika d8a46c9765 [ADF-640] reload document list on folder upload (#1895)
* reload document list on folder upload

- extend UploadService with 'folderCreated' event to be able reacting on folder uploads globally
- extend Demo Shell to reload document list on UploadService events (folderCreated)

* readme updates
2017-06-29 15:09:03 +01:00
Denys Vuika 9bb7d90670 [ADF-610] Upload button and DnD area should not upload hidden files and folders (#1908)
[ADF-610]  upload cleanup
- more strongly typing
- api improvements

* Upload cleanup and api improvements

- remove old unused settings (formFields variable)
- individual options for uploaded files (i.e. versioning)
- upload button and drag-and-drop area now set individual settings for file versioning

* exclude hidden files from upload
2017-06-29 15:09:03 +01:00
Eugenio Romano 2e1649e1da Merge pull request #1886 from Alfresco/dev-denys-ADF-535
[ADF-535] SASS support for components
2017-06-29 15:09:03 +01:00
Denys Vuika aa19904e5c SASS support for components
ability to use '.scss' files from within components
2017-06-29 15:09:03 +01:00
Eugenio Romano 2ab245ac72 Merge pull request #1904 from Alfresco/dev-denys-ADF-690
[ADF-690] fix upload area snackbar behaviour
2017-06-29 15:09:02 +01:00
Denys Vuika 53d693b900 fix upload area snackbar behaviour 2017-06-29 15:09:02 +01:00
7126 changed files with 270598 additions and 569733 deletions
+4 -16
View File
@@ -1,4 +1,5 @@
# Editor configuration, see http://editorconfig.org
# http://editorconfig.org
root = true
[*]
@@ -9,23 +10,10 @@ end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.json]
indent_style = space
indent_size = 2
[*.yaml]
indent_style = space
indent_size = 2
[*.yml]
[package.json]
indent_style = space
indent_size = 2
[*.md]
max_line_length = off
trim_trailing_whitespace = false
[resources/*.json]
indent_size = 2
max_line_length = off
insert_final_newline = false
trim_trailing_whitespace = false
-14
View File
@@ -1,14 +0,0 @@
.angular
nxcache
node_modules
dist
coverage
.github
.vscode
scripts
/angular.json
docs/**/*.md
lib/js-api/docs/**/*.md
.storybook
webpack.config.js
lib/core/src/lib/icon
-248
View File
@@ -1,248 +0,0 @@
module.exports = {
root: true,
ignorePatterns: ['projects/**/*', '**/node_modules/**/*', 'lib/cli/node_modules/**/*', '**/node_modules', '**/assets', '**/scripts', '**/docs'],
plugins: ['@nx'],
overrides: [
{
files: ['*.ts'],
parserOptions: {
project: ['tsconfig.json'],
createDefaultProgram: true
},
extends: [
'plugin:@nx/typescript',
'plugin:@nx/angular',
'plugin:@cspell/recommended',
'plugin:@angular-eslint/recommended',
'plugin:@angular-eslint/template/process-inline-templates',
'plugin:jsdoc/recommended-typescript-error'
// Uncomment this once all linting issues are fixed
// Note to developers:
// you can uncomment the full ruleset locally when fixing issues, and then comment
// that will allow splitting the work into smaller chunks
// 'plugin:unicorn/recommended'
],
plugins: [
'eslint-plugin-unicorn',
'eslint-plugin-rxjs',
'prettier',
'ban',
'license-header',
'@cspell',
'eslint-plugin-import',
'@angular-eslint/eslint-plugin',
'@typescript-eslint',
'jsdoc'
],
rules: {
// Uncomment this to enable prettier checks as part of the ESLint
// 'prettier/prettier': 'error',
'ban/ban': [
'error',
{ name: 'eval', message: 'Calls to eval is not allowed.' },
{ name: 'fdescribe', message: 'Calls to fdescribe is not allowed' },
{ name: 'fit', message: 'Calls to fit is not allowed' },
{ name: 'xit', message: 'Calls to xit is not allowed' },
{ name: 'xdescribe', message: 'Calls to xdescribe is not allowed' },
{ name: ['test', 'only'], message: 'Calls to test.only is not allowed' },
{ name: ['describe', 'only'], message: 'Calls to describe.only is not allowed' }
],
'@angular-eslint/component-selector': [
'error',
{
type: 'element',
prefix: ['adf', 'app'],
style: 'kebab-case'
}
],
'@angular-eslint/directive-selector': [
'error',
{
type: ['element', 'attribute'],
prefix: ['adf', 'app'],
style: 'kebab-case'
}
],
'@angular-eslint/no-host-metadata-property': 'off',
'@angular-eslint/no-input-prefix': 'error',
'@angular-eslint/prefer-inject': 'error',
'@typescript-eslint/consistent-type-definitions': 'error',
'@typescript-eslint/dot-notation': 'off',
'@typescript-eslint/explicit-member-accessibility': [
'off',
{
accessibility: 'explicit'
}
],
'@typescript-eslint/await-thenable': 'error',
'@typescript-eslint/prefer-optional-chain': 'warn',
'@typescript-eslint/prefer-readonly': 'error',
'@typescript-eslint/no-inferrable-types': 'off',
'@typescript-eslint/no-require-imports': 'off',
'@typescript-eslint/no-var-requires': 'error',
'@typescript-eslint/naming-convention': [
'error',
{
selector: [
'classProperty',
'objectLiteralProperty',
'typeProperty',
'classMethod',
'objectLiteralMethod',
'typeMethod',
'accessor',
'enumMember'
],
format: null,
modifiers: ['requiresQuotes']
}
],
'@typescript-eslint/member-ordering': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'prefer-promise-reject-errors': 'error',
'brace-style': 'off',
'comma-dangle': 'error',
'default-case': 'error',
'import/order': 'off',
'max-len': [
'error',
{
code: 240
}
],
'no-bitwise': 'off',
'no-console': [
'error',
{
allow: [
'warn',
'dir',
'timeLog',
'assert',
'clear',
'count',
'countReset',
'group',
'groupEnd',
'table',
'dirxml',
'error',
'groupCollapsed',
'Console',
'profile',
'profileEnd',
'timeStamp',
'context'
]
}
],
'no-duplicate-imports': 'error',
'no-multiple-empty-lines': 'error',
'no-redeclare': 'off',
'@typescript-eslint/no-redeclare': ['off', { ignoreDeclarationMerge: true }],
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
caughtErrorsIgnorePattern: '^_'
}
],
'no-return-await': 'error',
'rxjs/no-create': 'error',
'rxjs/no-subject-unsubscribe': 'error',
'rxjs/no-subject-value': 'error',
'rxjs/no-unsafe-takeuntil': 'error',
'unicorn/filename-case': 'error',
'unicorn/prefer-optional-catch-binding': 'error',
'@typescript-eslint/no-unused-expressions': [
'error',
{
allowShortCircuit: true,
allowTernary: true
}
],
'license-header/header': [
'error',
[
'/*!',
' * @license',
' * Copyright © 2005-2025 Hyland Software, Inc. and its affiliates. All rights reserved.',
' *',
' * 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.',
' */'
]
],
'no-restricted-syntax': [
'error',
{
selector: "Identifier[name='CUSTOM_ELEMENTS_SCHEMA']",
message: 'The use of CUSTOM_ELEMENTS_SCHEMA is not allowed. Consider alternatives for proper schema handling.'
},
{
selector: "Identifier[name='NO_ERRORS_SCHEMA']",
message: 'The use of NO_ERRORS_SCHEMA is not allowed. Consider alternatives for proper schema handling.'
},
{
selector: 'TSEnumDeclaration',
message: 'Enums are not allowed. Use string literal types (e.g., type Foo = "a" | "b") or const objects instead.'
},
{
selector: ':matches(Literal[value=/ng-reflect-/], TemplateElement[value.cooked=/ng-reflect-/])',
message: '*ng-reflect-* attributes should not be used. Consider alternatives for proper selectors.'
}
]
}
},
{
files: ['*.html'],
extends: ['plugin:@angular-eslint/template/recommended', 'plugin:@angular-eslint/template/accessibility'],
parser: '@angular-eslint/template-parser',
rules: {
'@angular-eslint/template/prefer-self-closing-tags': 'error'
}
},
{
files: ['*.spec.ts'],
plugins: ['@alfresco/eslint-angular'],
rules: {
'@alfresco/eslint-angular/no-angular-material-selectors': 'error',
'@angular-eslint/component-class-suffix': 'off'
}
},
{
files: ['*.ts'],
extends: ['plugin:@angular-eslint/template/process-inline-templates'],
excludedFiles: ['*.spec.ts']
},
{
files: ['*.json'],
parser: 'jsonc-eslint-parser',
rules: {
'comma-dangle': ['error', 'never']
}
},
{
files: ['**/*.stories.ts'],
rules: {
'@cspell/spellchecker': 'off'
}
}
],
extends: ['plugin:storybook/recommended']
};
-3
View File
@@ -1,3 +0,0 @@
{
"extends": ["./.eslintrc.js"]
}
-1
View File
@@ -1 +0,0 @@
.github/workflows/*.lock.yml linguist-generated=true merge=ours
-18
View File
@@ -1,18 +0,0 @@
# Each line is a file pattern followed by one or more owners.
# These owners will be the default owners for everything in
# the repo. Unless a later match takes precedence,
# these users will be requested for
# review when someone opens a pull request.
* @eromano
# Order is important; the last matching pattern takes the most
# precedence. When someone opens a pull request that only
# modifies JS files, only @js-owner and not the global
# owner(s) will be requested for a review.
/e2e/ @eromano
# The `docs/*` pattern will match files like
# `docs/getting-started.md` but not further nested files like
# `docs/build-app/troubleshooting.md`.
/docs/ @eromano
-89
View File
@@ -1,89 +0,0 @@
name: "before-install"
description: "launch before_install.sh and then parse env vars"
inputs:
act:
description: 'enable act debug'
required: false
type: boolean
default: 'false'
runs:
using: "composite"
steps:
- name: base vars
shell: bash
run: |
if [ -n "${GITHUB_BASE_REF:-}" ]; then
BASE_HASH=$(git merge-base "origin/${GITHUB_BASE_REF}" HEAD 2>/dev/null || git rev-parse HEAD)
else
BASE_HASH=$(git rev-parse HEAD)
fi
{
echo "GIT_HASH=$(git rev-parse HEAD)";
echo "BASE_HASH=${BASE_HASH}";
echo "HEAD_HASH=HEAD";
echo "HEAD_COMMIT_HASH=${GH_COMMIT}";
echo "NX_CALCULATION_FLAGS=--all";
echo "BUILD_OPTS=--configuration production";
echo CI_FORCE_RUN=false;
echo NODE_VERSION=$(node -v);
} >> $GITHUB_ENV
- name: affected:* flag parser
shell: bash
env:
EVENT_NAME: ${{ github.event_name }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Get commit message safely from git to avoid script injection
# For PRs, use the PR head SHA; for other events use HEAD
if [ "$EVENT_NAME" == "pull_request" ] && [ -n "$PR_HEAD_SHA" ]; then
COMMIT_MSG=$(git log -1 --format=%B "$PR_HEAD_SHA" 2>/dev/null || echo "")
else
COMMIT_MSG=$(git log -1 --format=%B 2>/dev/null || echo "")
fi
if echo "$COMMIT_MSG" | grep -qF "[affected:*]"; then
echo "Setting up CI to run with commit flag [affected:*] flag."
echo "BREAK_ACTION=true" >> $GITHUB_ENV
fi
- name: PULL_REQUEST event
if: ${{ env.BREAK_ACTION == false && github.event_name == 'pull_request' && !github.event.pull_request.merged }}
shell: bash
run: |
echo "Setting up CI flags for Pull Request event"
NX_CALCULATION_FLAGS="--base=origin/${GITHUB_BASE_REF} --head=$HEAD_HASH"
{
echo "NX_CALCULATION_FLAGS=$NX_CALCULATION_FLAGS";
echo "BASE_HASH=origin/${GITHUB_BASE_REF}";
echo "BREAK_ACTION=true";
} >> $GITHUB_ENV
- name: RELEASE on master/develop patch branch
if: ${{ env.BREAK_ACTION == false && (github.event.pull_request.merged || github.event_name == 'push') }}
shell: bash
env:
REF_NAME: ${{ github.ref_name }}
run: |
if [[ "$REF_NAME" =~ ^master(-patch.*)?$ ]]; then
# into master(-patch*)
echo "Setting up CI flags for Push on master patch"
elif [[ "$REF_NAME" =~ ^develop-patch.*$ ]]; then
# into develop-patch*
echo "Setting up CI flags for Push develop patch"
else
echo "Setting up CI flags for Push on develop branch"
# base=$(git describe --tags $(git rev-list --tags --max-count=1))
# we publish always all the libs until we don't handle partial release
echo "NX_CALCULATION_FLAGS=--all" >> $GITHUB_ENV
fi
echo "BREAK_ACTION=true" >> $GITHUB_ENV
- name: SCHEDULE event
if: ${{ github.event_name == 'schedule' }}
shell: bash
env:
EV_NAME: ${{ github.event_name }}
run: |
echo "Setting up CI to run on SCHEDULE"
echo "NX_CALCULATION_FLAGS=--all" >> $GITHUB_ENV
-23
View File
@@ -1,23 +0,0 @@
name: Git tag creation
description: 'Creates a git tag in the specified repository for a given commit.'
inputs:
tagName:
description: 'The github tag to be created'
required: true
releaseNote:
description: 'The github release note to be created'
required: false
runs:
using: 'composite'
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
name: Create git tag
env:
TAG_NAME: ${{ inputs.tagName }}
RELEASE_NOTE: ${{ inputs.releaseNote }}
with:
script: |
const createGitTag = require('./.github/actions/create-git-tag/create-git-tag.js');
await createGitTag({ core, github, context, tagName: process.env.TAG_NAME });
@@ -1,42 +0,0 @@
/*!
* @license
* Copyright © 2005-2023 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* 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.
*/
module.exports = async ({ github, context, core, tagName }) => {
const tagSHA = context.payload?.after ?? context.sha;
core.notice(`Creating tag with title: ${tagName}, and SHA: ${tagSHA}`);
const createdTag = await github.rest.git.createTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: tagName,
message: 'Release note',
object: tagSHA,
type: 'commit'
});
const createdRef = await github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: 'refs/tags/' + tagName,
sha: createdTag.data.sha
});
if (createdRef.status === 201) {
core.notice(`Tag ${tagName} was created successfully`);
}
};
@@ -1,43 +0,0 @@
name: "Download build artifacts"
description: "Download build artifacts"
runs:
using: "composite"
steps:
- name: Restore dist from cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: dist
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
dist-${{ github.run_id }}-
fail-on-cache-miss: true
- name: Restore nxcache from cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: nxcache
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
nxcache-${{ github.run_id }}-
fail-on-cache-miss: true
- name: Restore node_modules from cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: node_modules
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
restore-keys: |
node-modules-${{ github.run_id }}-
fail-on-cache-miss: true
- name: show files
shell: bash
run: |
pwd
ls -lha
echo "====DIST===="
find dist -maxdepth 1 -type d
echo "====NXCACHE===="
find nxcache -maxdepth 1 -type d
echo "====ADF===="
find node_modules/@alfresco/ -maxdepth 1 -type d
-32
View File
@@ -1,32 +0,0 @@
name: 'enable dryrun'
description: 'check if must run pipeline in dryrun mode'
inputs:
dry-run-flag:
description: 'enable dryrun'
required: false
type: boolean
default: true
outputs:
dryrun:
description: "long sha of the tag"
value: ${{ steps.dryrun.outputs.dryrun }}
runs:
using: "composite"
steps:
- name: set dryrun flag to TRUE
shell: bash
id: dryrun
env:
DRY_RUN_FLAG: ${{ inputs.dry-run-flag }}
run: |
if [[ "$DRY_RUN_FLAG" == 'true' ]]; then
echo "dryrun=--dry-run" >> $GITHUB_OUTPUT;
echo "enabling dryrun"
else
echo "dryrun=" >> $GITHUB_OUTPUT;
echo "dryrun NOT enabled"
fi
@@ -1,19 +0,0 @@
name: 'Get tag sha'
description: 'get the sha of the latest or a specific tag'
outputs:
tag_sha:
description: "long sha of the tag"
value: ${{ steps.sha_out.outputs.tag_sha }}
runs:
using: "composite"
steps:
- name: get tag short sha
shell: bash
id: sha_out
run: |
tag_sha=$(git rev-list -n 1 $(git tag --sort=-creatordate | head -n 1))
echo "tag_sha=$tag_sha" >> $GITHUB_OUTPUT
echo $tag_sha
@@ -1,31 +0,0 @@
name: 'Check NPM bundle'
description: 'check npm bundle'
inputs:
branch_name:
description: "override GITHUB_REF_NAME"
required: false
default: ${{ github.ref_name }}
runs:
using: "composite"
steps:
- name: load "NPM TAG"
id: set-npm-tag
uses: ./.github/actions/set-npm-tag
with:
branch_name: ${{ inputs.branch_name }}
- name: check npm bundle
shell: bash
id: sha_out
env:
TAG_NPM: ${{ steps.set-npm-tag.outputs.npm-tag }}
run: |
if [[ -z $TAG_NPM ]]; then
echo "TAG_NPM not set, aborting"
exit 1
fi
ADF_VERSION=$(npm view @alfresco/adf-core@${TAG_NPM} version)
echo "check bundle on TAG_NPM='${TAG_NPM}' and ADF_VERSION='${ADF_VERSION}'"
./scripts/github/build/npm-check-bundles.sh -v ${ADF_VERSION}
-17
View File
@@ -1,17 +0,0 @@
name: 'Save Nx Cache'
description: 'Save Nx cache and dist outputs only when the job succeeds'
inputs:
cache-suffix:
description: 'Must match the cache-suffix used in the setup action'
required: true
runs:
using: "composite"
steps:
- name: Save nx cache
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
nxcache
.nx
dist
key: ${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-${{ hashFiles('nx.json') }}-${{ github.sha }}
-45
View File
@@ -1,45 +0,0 @@
name: "set npm tag"
description: "se NPM tag"
inputs:
branch_name:
description: "override GITHUB_REF_NAME"
required: false
default: ${{ github.ref_name }}
outputs:
npm-tag:
description: "NPM tag"
value: ${{ steps.set-npm-tag.outputs.npm-tag }}
runs:
using: "composite"
steps:
- name: set TAG_NPM
id: set-npm-tag
shell: bash
env:
BRANCH_NAME: ${{ inputs.branch_name }}
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
TAG_NPM="branch"
else
TAG_NPM="alpha"
VERSION_IN_PACKAGE_JSON=$(node -p "require('./package.json')".version)
echo "version in package.json=${VERSION_IN_PACKAGE_JSON}"
if [[ $BRANCH_NAME =~ ^master(-patch.*)?$ ]]; then
# Pre-release versions
if [[ $VERSION_IN_PACKAGE_JSON =~ ^[0-9]*\.[0-9]*\.[0-9]*-A\.[0-9]*$ ]]; then
TAG_NPM=next
# Stable major versions
else
TAG_NPM=latest
fi
fi
if [[ $BRANCH_NAME =~ ^develop(-patch.*)?$ ]]; then
TAG_NPM=alpha
fi
fi
echo "npm-tag=$TAG_NPM" >> $GITHUB_OUTPUT
echo "Computed tag: $TAG_NPM"
-64
View File
@@ -1,64 +0,0 @@
name: 'Setup'
description: 'Initialize cache, env var load'
inputs:
cache-suffix:
description: 'Suffix to make Nx cache key unique per job (e.g. matrix project name)'
required: false
default: 'default'
full-setup:
description: 'Run git-latest-tag, npm-tag, and before-install (requires fetch-depth: 0). Set to false for matrix jobs that only need node/cache.'
required: false
type: boolean
default: 'true'
act:
description: 'enable act debug'
required: false
type: boolean
default: 'false'
outputs:
npm-tag:
description: 'NPM tag'
value: ${{ steps.set-npm-tag.outputs.npm-tag }}
runs:
using: "composite"
steps:
- name: Set consistent machine ID for Nx cache
shell: bash
run: echo "nx-github-actions" | sudo tee /etc/machine-id > /dev/null
- name: Setup pnpm
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
- name: Setup Node
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version-file: '.nvmrc'
cache: 'pnpm'
- name: get latest tag sha
if: ${{ inputs.full-setup == 'true' }}
id: tag-sha
uses: Alfresco/alfresco-build-tools/.github/actions/git-latest-tag@1d671f8f10336861c89c67be57c6648d98876103 # v18.19.0
- name: load "NPM TAG"
if: ${{ inputs.full-setup == 'true' }}
id: set-npm-tag
uses: ./.github/actions/set-npm-tag
- name: Install dependencies
shell: bash
run: pnpm install --frozen-lockfile
- name: Security audit
shell: bash
run: pnpm audit --audit-level=critical
- name: Restore nx cache
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: |
nxcache
.nx
dist
key: ${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-${{ hashFiles('nx.json') }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-${{ hashFiles('nx.json') }}-
${{ runner.os }}-nxcache-${{ inputs.cache-suffix }}-
- name: before install script
if: ${{ inputs.full-setup == 'true' }}
uses: ./.github/actions/before-install
with:
act: ${{ inputs.act }}
@@ -1,25 +0,0 @@
name: "Upload build artifacts"
description: "Upload build artifacts"
runs:
using: "composite"
steps:
- name: Save dist to cache
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: dist
key: dist-${{ github.run_id }}-${{ github.run_attempt }}
- name: Save nxcache to cache
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: nxcache
key: nxcache-${{ github.run_id }}-${{ github.run_attempt }}
- name: Save node_modules to cache
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: node_modules
key: node-modules-${{ github.run_id }}-${{ github.run_attempt }}
-5
View File
@@ -1,5 +0,0 @@
name: "CodeQL config"
paths-ignore:
- 'e2e/resources/**'
- 'docs/**'
-78
View File
@@ -1,78 +0,0 @@
# General Code Review Instructions
## Review Priorities
When performing a code review, prioritize issues in the following order:
🔴 CRITICAL (Block merge)
* Security: Vulnerabilities, exposed secrets, authentication/authorization issues, injection, XSS
* Memory/resource leaks
* Crashes or undefined behavior
* Correctness: Logic errors, data corruption risks, race conditions, missing error handling
* Data Loss: Risk of data loss or corruption
🟡 IMPORTANT (Requires discussion)
* Code Quality: Severe violations of SOLID principles, excessive duplication
* Test Coverage: Missing tests for critical paths or new functionality
* Performance: Obvious performance bottlenecks (N+1 queries, memory leaks)
* Architecture: Significant deviations from established patterns
🟢 SUGGESTION (Non-blocking improvements)
* Readability: Poor naming, complex logic that could be simplified
* Optimization: Performance improvements without functional impact
* Best Practices: Minor deviations from conventions
* Documentation: Missing or incomplete comments/documentation
## General Review Principles
When performing a code review, follow these principles:
* Be specific: Reference exact lines, files, and provide concrete examples
* Be pragmatic: Not every suggestion needs immediate implementation
* Provide context: Explain WHY something is an issue and the potential impact
* Suggest solutions: Show corrected code when applicable, not just what's wrong
* Be constructive: Focus on improving the code, not criticizing the author
* Recognize good practices: Acknowledge well-written code and smart solutions
* Group related comments: Avoid multiple comments about the same topic
* Ask clarifying questions when code intent is unclear
## Code Quality Standards
When performing a code review, check for:
### Clean Code
* Descriptive and meaningful names for variables, functions, and classes
* Single Responsibility Principle: each function/class does one thing well
* DRY (Don't Repeat Yourself): no code duplication
* Functions should be small and focused (ideally < 20-30 lines)
* Avoid deeply nested code (max 3-4 levels), unit tests should be an exception from this rule
* Avoid magic numbers and strings (use constants)
* Code should be self-documenting; comments only when necessary
* Code follows consistent style and conventions
* No commented-out code or TODO without tickets
## Error Handling
* Proper error handling at appropriate levels
* Meaningful error messages
* No silent failures or ignored exceptions
* Fail fast: validate inputs early
* Use appropriate error types/exceptions
## Testing Standards
When performing a code review, verify test quality:
* Coverage: Critical paths and new functionality must have tests
* Test Names: Descriptive names that explain what is being tested
* Independence: Tests should not depend on each other or external state
* Assertions: Use specific assertions, avoid generics
* Edge Cases: Test boundary conditions, null values, empty inputs
* Mock Appropriately: Mock external dependencies, not domain logic
* New code has appropriate test coverage
* No tests that always pass or are commented out
## Architecture and Design
When performing a code review, verify architectural principles:
* Separation of Concerns: Clear boundaries between layers/modules
* Dependency Direction: High-level modules don't depend on low-level details
* Interface Segregation: Prefer small, focused interfaces
* Loose Coupling: Components should be independently testable
* High Cohesion: Related functionality grouped together
* Consistent Patterns: Follow established patterns in the codebase
-60
View File
@@ -1,60 +0,0 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: "weekly"
day: "sunday"
time: "07:00"
cooldown:
default-days: 3
open-pull-requests-limit: 5
target-branch: develop
groups:
angular:
patterns:
- "@angular/*"
angular-devkit:
patterns:
- "@angular-devkit/*"
ngrx:
patterns:
- "@ngrx/*"
nrwl:
patterns:
- "@nrwl/*"
typescript-eslint:
patterns:
- "@typescript-eslint/*"
ignore:
- dependency-name: "pdfjs-dist"
- dependency-name: "@types/*"
- dependency-name: "typescript"
- package-ecosystem: "github-actions"
directories:
- "/"
- "/.github/actions/before-install"
- "/.github/actions/create-git-tag"
- "/.github/actions/download-node-modules-and-artifacts"
- "/.github/actions/enable-dryrun"
- "/.github/actions/get-latest-tag-sha"
- "/.github/actions/npm-check-bundle"
- "/.github/actions/save-nx-cache"
- "/.github/actions/set-npm-tag"
- "/.github/actions/setup"
- "/.github/actions/upload-node-modules-and-artifacts"
schedule:
interval: "weekly"
cooldown:
default-days: 3
groups:
github-actions:
patterns:
- "*"
update-types:
- "minor"
- "patch"
ignore:
# Managed by gh aw add. Version-locked to the gh-aw compiler; do not bump.
- dependency-name: "github/gh-aw-actions"
-23
View File
@@ -1,23 +0,0 @@
---
applyTo: "**/*.html"
---
# HTML Development Standards
* Simple Templates: Keep templates as simple as possible, avoiding complex logic directly in the template. Delegate complex logic to the component's TypeScript code.
* Native Control Flow: Use the new built-in control flow syntax (`@if`, `@for`, `@switch`) instead of the older structural directives (`*ngIf`, `*ngFor`, `*ngSwitch`).
* NgOptimizedImage: Use `NgOptimizedImage` for all static images to automatically optimize image loading and performance.
* Async Pipe: Use the `async` pipe to handle observables in templates. This automatically subscribes and unsubscribes, preventing memory leaks.
* Prefer pipes over functions in templates for performance reasons, as pipes are only re-evaluated when their inputs change.
## Accessibility Standards
* Add `alt` text to all images
* Label form inputs with `<mat-label>` or `aria-label`
* Ensure interactive elements have accessible names
* Add `role`, `aria-labelledby`, and `aria-describedby` when semantic HTML isn't sufficient
* All interactive elements must be keyboard accessible
* Ensure 4.5:1 contrast ratio for normal text, 3:1 for large text
* Use `aria-live="polite"` for status updates
* Watch out for misused/non-semantic elements (e.g., <div> instead of <section>)
* Avoid broken heading hierarchy (e.g., h1 → h3 without h2)
-19
View File
@@ -1,19 +0,0 @@
---
applyTo: "**/*.scss"
---
# SCSS Development Standards
* Avoid using `!important` to override styles unless absolutely necessary; instead, increase specificity or refactor the code structure.
* Avoid using Angular Material internal class; prefer using Angular Material Design 3 theming and tokens.
* Use variables for colors, fonts, and other design tokens to maintain consistency across the project.
* Use mixins for reusable styles and to avoid code duplication.
* Ensure that styles are responsive and work well across different screen sizes and devices.
* Use CSS Grid and Flexbox for layout to create flexible and responsive designs.
* Avoid using overly specific selectors (e.g., #header .nav ul li a)
* Be DRY (avoid repeated styles for similar elements)
* Check for inconsistent naming (e.g., mixing BEM and arbitrary classes)
* Make sure selected colors have right contrast (satisfy WCAG AA)
* All interactive elements should have focus state
* Avoid disabled outline without alternative focus indicators
-96
View File
@@ -1,96 +0,0 @@
---
applyTo: "**/*.ts"
---
# TypeScript Development Standards
## Type Safety
* Strict Type Checking: Always enable and adhere to strict type checking. This helps catch errors early and improves code quality.
* Prefer Type Inference: Allow TypeScript to infer types when they are obvious from the context. This reduces verbosity while maintaining type safety.
* Avoid `any`: Do not use the `any` type unless absolutely necessary as it bypasses type checking. Prefer `unknown` when a type is uncertain and you need to handle it safely.
* Use strict null checks (no `null` or `undefined` without explicit handling)
* Use type guards and union types for robust type checking
* Check for missing return types in function signatures
* Avoid implicit `any` (untyped function parameters)
## Naming Conventions
* Use PascalCase for types, interfaces, and classes
* Use camelCase for variables, functions, and methods
* Use UPPER_CASE for constants
## Modern TypeScript Patterns
* Use optional chaining (`?.`) and nullish coalescing (`??`)
* Prefer `const` over `let`; never use `var`
* Use arrow functions for callbacks and short functions
* Avoid enums - they generate additional code at compile time, which increases the size of the final file. This can have a negative impact on the loading speed and performance of the app. Prefer union types or literal types instead.
* Avoid unhandled promise rejections (missing .catch() or try/catch)
* Use proper async/await pattern
* Avoid inefficient array operations (e.g., nested .map())
* Use destructuring for object/array access
* Prefer arrow functions
## Angular Best Practices
* Standalone Components: Always use standalone components, directives, and pipes. Avoid using `NgModules` for new features or refactoring existing ones.
* Implicit Standalone: When creating standalone components, you do not need to explicitly set `standalone: true` inside the `@Component`, `@Directive` and `@Pipe` decorators, as it is implied by default.
* Lazy Loading: Implement lazy loading for feature routes to improve initial load times of your application.
* Use Angular Material or other modern UI libraries for consistent styling and UI components.
* Implement proper error handling with RxJS operators (e.g., catchError)
* Verify if newly added functionalities can utilize Angular Signals for fine-grained reactivity, reducing change detection overhead.
* Utilize AOT (Ahead-of-Time) compilation and tree-shaking for efficient, smaller bundle sizes.
* Prefer class binding over `ngClass` and `ngStyle` for better performance.
* Use protected on class members that are only used by a component's template, as it allows for better encapsulation while still being accessible to the template.
* Use readonly for properties that shouldn't change.
* Use `takeUntilDestroyed` & `destroyRef`: The `takeUntilDestroyed` and `destroyRef` have been introduced with Angular 16 and help to reduce boilerplate code related to unsubscribing on the `OnDestroy` hook.
* Organize the order of properties and methods in Angular components for readability and maintainability. Recommended order is:
1. **Injected services** Whether they are public or private, it's clear they are dependencies of the class.
2. **Inputs**: Properties that receive data from outside.
3. **Outputs**: Events that the component can trigger.
4. **ViewChild/ContentChild**: References to HTML elements.
5. **Public static properties**: Constants and static members that are accessible to everyone.
6. **Readonly properties**: Immutable public properties.
7. **Public properties**: Data and functions available to everyone.
8. **Private static properties**: Constants and static members that are only accessible within the class.
9. **Private readonly properties**: Immutable private properties.
10. **Private properties**: Data and functions used only inside the component.
11. **Setters and Getters**: Methods for accessing and modifying properties.
12. **Constructor**: Used to initialize the component.
13. **Lifecycle Hooks**: Methods that run at specific times in the components lifecycle.
14. **Public methods**: Functions available to everyone.
15. **Private methods**: Functions used only inside the component.
## Components
* Single Responsibility: Keep components small, focused, and responsible for a single piece of functionality.
* Reactive Forms: Prefer Reactive forms over Template-driven forms for complex forms, validation, and dynamic controls due to their explicit, immutable, and synchronous nature.
* Use Typed Forms: Typed Forms in Angular are a new feature introduced in Angular 14 that provide stronger type checking for reactive forms. They allow developers to define the structure and types of form controls, making it easier to catch errors at compile-time rather than runtime.
## Services
* Single Responsibility: Design services around a single, well-defined responsibility.
* `providedIn: 'root'`: Use the `providedIn: 'root'` option when declaring injectable services to ensure they are singletons and tree-shakable.
* `inject()` Function: Prefer the `inject()` function over constructor injection when injecting dependencies, especially within `provide` functions, `computed` properties, or outside of constructor context.
## Unit testing
* Write unit tests for components, services, and pipes using Jasmine and Karma.
* Test cases should be reasonably groupped based on tested functionality/behaviour using describe blocks.
* Use plain English test names based on the should <expectedBehavior> when <stateUnderTest> pattern as a guideline.
* Use Angular's TestBed for component testing with mocked dependencies
* Avoid Direct Calls to Component Lifecycle Hooks: Instead of directly invoking lifecycle hooks like `ngOnInit()`, use Angular's testing utilities to trigger them naturally. For example, use `fixture.detectChanges()` to trigger change detection, which will automatically call `ngOnInit()` and other lifecycle hooks in the correct order.
* Use fixture.componentRef.setInput() Instead of Direct Input Assignment: When testing components with inputs, use `fixture.componentRef.setInput()` to set input values. This method ensures that Angular's change detection is properly triggered, allowing the component to react to input changes as it would in a real application.
* Use the Provide Mock Store for testing components that rely on NgRx state management. This allows you to mock the store and control the state during tests without needing to set up a full NgRx environment.
* Mock HTTP requests using provideHttpClientTesting
* Import only the minimal required modules
* Avoid NO_ERRORS_SCHEMA and CUSTOM_ELEMENTS_SCHEMA in tests to ensure proper error detection
* Do not verify mocked methods
* Avoid mocking component methods unless necessary; prefer testing actual behavior
* Avoid testing private methods directly; test them through public methods instead
* Avoid testing methods or behaviours of children components; use shallow testing or mock child components instead
* Use the overrideProviders API to replace components, directives, pipes, or services declared deep within the module hierarchy
* Avoid async/await in synchronous unit tests
* Prefer data-automation-id over CSS class when possible
* Do not use toBeDefined() to check if an element is visible.
-39
View File
@@ -1,39 +0,0 @@
name: "Build Lib Workflow"
on:
workflow_call:
inputs:
base_ref:
description: 'Base branch for affected calculation'
required: false
type: string
default: 'develop'
env:
NODE_OPTIONS: "--max-old-space-size=5120"
jobs:
build:
name: "Build affected libs"
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Setup environment
id: setup-env
uses: ./.github/actions/setup
with:
cache-suffix: build
full-setup: 'false'
- name: Build affected libs
env:
BASE_REF: ${{ inputs.base_ref }}
run: pnpm nx affected --target=build --base=origin/$BASE_REF --head=HEAD --configuration=production --exclude=stories
- name: Save nx cache
if: ${{ success() }}
uses: ./.github/actions/save-nx-cache
with:
cache-suffix: build
-56
View File
@@ -1,56 +0,0 @@
name: "CodeQL"
on:
push:
branches: [develop, master]
paths-ignore:
- 'e2e/resources/**'
- 'docs/**'
pull_request:
# The branches below must be a subset of the branches above
branches: [develop]
paths-ignore:
- 'e2e/resources/**'
- 'docs/**'
schedule:
- cron: '0 5 * * 0'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v3.29.5
# Override language selection by uncommenting this and choosing your languages
with:
languages: javascript
config-file: ./.github/codeql/codeql-config.yml
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a # v3.29.5
# ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v3.29.5
-41
View File
@@ -1,41 +0,0 @@
name: Package published
on:
registry_package:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
if: github.event.registry_package.package_type == 'npm' && github.event.registry_package.name == 'adf-core'
steps:
- name: Generate app token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.GH_APP_ENGINEERING_CONTRIB_CLIENT_ID }}
private-key: ${{ secrets.GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: alfresco-apps
permission-contents: write
- name: Dispatch event to monorepo
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PACKAGE_NAME: ${{ github.event.registry_package.name }}
PACKAGE_VERSION: ${{ github.event.registry_package.package_version.name }}
with:
github-token: ${{ steps.app-token.outputs.token }}
retries: 3
script: |
const payload = {
package_name: process.env.PACKAGE_NAME,
package_version: process.env.PACKAGE_VERSION
};
await github.rest.repos.createDispatchEvent({
owner: context.repo.owner,
repo: "alfresco-apps",
event_type: "package-published",
client_payload: payload
});
console.log(`Trigger a dispatch event for the monorepo`);
-46
View File
@@ -1,46 +0,0 @@
name: Pull Translations from Crowdin
on:
schedule:
- cron: "0 7-17 * * 1-5"
workflow_dispatch:
workflow_call:
secrets:
GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY:
required: true
CROWDIN_TRANSLATIONS_TOKEN:
required: true
HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY:
required: true
jobs:
pull-from-crowdin:
runs-on: ubuntu-latest
steps:
- name: Generate app token
id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.GH_APP_ENGINEERING_CONTRIB_CLIENT_ID }}
private-key: ${{ secrets.GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: develop
token: ${{ steps.app-token.outputs.token }}
- name: Pull translations from Crowdin
uses: crowdin/github-action@e0c8f73cdc0fafde9396e056c5038217000a32d1 # v2.16.4
with:
skip_ref_checkout: true
upload_sources: false
download_translations: true
create_pull_request: true
localization_branch_name: automated-translations-update
pull_request_title: "GH auto: Automated Update of Translations from Crowdin"
pull_request_base_branch_name: develop
github_user_name: ${{ vars.HXPS_GIT_USERNAME }}
github_user_email: ${{ vars.HXPS_GIT_EMAIL }}
gpg_private_key: ${{ secrets.HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY }}
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
CROWDIN_TOKEN: ${{ secrets.CROWDIN_TRANSLATIONS_TOKEN }}
-342
View File
@@ -1,342 +0,0 @@
name: "pull-request"
on:
workflow_call:
inputs:
dry-run-flag:
description: "enable dry-run on artifact push"
required: false
type: boolean
default: true
devel:
description: "devel"
required: false
type: boolean
default: false
cron-run:
description: "disables jobs which should not run when cron runs e2es"
required: false
type: boolean
default: false
pull_request:
types: [opened, synchronize, reopened]
branches:
- develop
- master
- develop-patch*
- master-patch*
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
GH_COMMIT: ${{ github.sha }}
NODE_OPTIONS: "--max-old-space-size=5120"
jobs:
pre-checks:
runs-on: ubuntu-latest
outputs:
code-changed: ${{ steps.path-filter.outputs.code-changed }}
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Ensure SHA pinned actions
uses: hyland/github-actions-ensure-sha-pinned-actions@7957efb76aba0eec7580a9c0392d3e5bec381359 # v2.0.1
- name: Check pnpm-lock.yaml version
run: |
if [[ -f "pnpm-lock.yaml" ]]; then
LOCKFILE_VERSION=$(grep "^lockfileVersion:" pnpm-lock.yaml | cut -d"'" -f2)
if [[ "$LOCKFILE_VERSION" == "9.0" ]]; then
echo "pnpm-lock.yaml has correct version: $LOCKFILE_VERSION"
else
echo "pnpm-lock.yaml must be version 9.0, found: $LOCKFILE_VERSION"
exit 1
fi
else
echo "pnpm-lock.yaml is missing"
exit 1
fi
- name: Detect code changes
id: path-filter
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "Not a PR event — assuming code changed"
echo "code-changed=true" >> $GITHUB_OUTPUT
exit 0
fi
FILES=$(gh api /repos/$GITHUB_REPOSITORY/pulls/${{ github.event.pull_request.number }}/files --paginate --jq '.[].filename')
CODE_CHANGED="false"
while IFS= read -r file; do
case "$file" in
*.md|docs/*|.github/*.md|.github/CODEOWNERS|.github/dependabot.yml|LICENSE*|NOTICE*|.editorconfig|.gitattributes)
;;
*)
CODE_CHANGED="true"
break
;;
esac
done <<< "$FILES"
echo "code-changed=$CODE_CHANGED" >> $GITHUB_OUTPUT
echo "Code changed: $CODE_CHANGED"
check-if-pr-is-approved:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
if: ${{ github.event_name == 'pull_request' }}
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1
- name: Check if PR approval can be skipped
id: skip-check
env:
EVENT_NAME: ${{ github.event_name }}
ACTOR: ${{ github.actor }}
DEVEL_FLAG: ${{ inputs.devel }}
PR_TITLE: ${{ github.event.pull_request.title }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
skip="false"
# Get commit message safely from git to avoid script injection
if [ "$EVENT_NAME" == "pull_request" ] && [ -n "$PR_HEAD_SHA" ]; then
COMMIT_MESSAGE=$(git log -1 --format=%B "$PR_HEAD_SHA" 2>/dev/null || echo "")
else
COMMIT_MESSAGE=$(git log -1 --format=%B 2>/dev/null || echo "")
fi
if [ "$EVENT_NAME" == "schedule" ] || [ "$EVENT_NAME" == "workflow_dispatch" ]; then
echo -e "\033[32mSchedule/dispatch event — skipping approval check\033[0m"
skip="true"
elif [ "$ACTOR" == "dependabot[bot]" ] || [ "$ACTOR" == "alfresco-build" ]; then
echo -e "\033[32mCommit by $ACTOR — skipping approval check\033[0m"
skip="true"
elif echo "$PR_TITLE" | grep -qF "[ci:force]"; then
echo -e "\033[32m[ci:force] flag detected in PR title — skipping approval check\033[0m"
skip="true"
elif echo "$COMMIT_MESSAGE" | grep -qF "[ci:force]"; then
echo -e "\033[32m[ci:force] flag detected in commit message — skipping approval check\033[0m"
skip="true"
elif [[ "$DEVEL_FLAG" == "true" ]]; then
echo -e "\033[32mDevel flag — skipping approval check\033[0m"
skip="true"
fi
echo "skip=$skip" >> $GITHUB_OUTPUT
- name: Get PR number
if: ${{ steps.skip-check.outputs.skip != 'true' }}
id: pr-number
env:
GH_TOKEN: ${{ github.token }}
run: |
PR_NUMBER="${{ github.event.pull_request.number }}"
if [ -z "$PR_NUMBER" ]; then
PR_NUMBER=$(gh pr view --json number --jq '.number' 2>/dev/null || echo "")
fi
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "PR: $PR_NUMBER"
- name: Check if PR is approved
if: ${{ steps.skip-check.outputs.skip != 'true' && steps.pr-number.outputs.pr_number != '' }}
env:
GH_TOKEN: ${{ github.token }}
PR_NUMBER: ${{ steps.pr-number.outputs.pr_number }}
run: |
echo "Checking approval for PR: $PR_NUMBER"
checkApproval=$(gh api /repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews | jq '.[] | select(.state == "APPROVED") | .user.login')
if [[ $checkApproval ]]; then
echo -e "\033[32mPR approved\033[0m"
else
echo -e "\033[31mPR NOT approved\033[0m"
exit 1
fi
setup:
timeout-minutes: 30
name: "Setup"
runs-on: ubuntu-latest
needs: [check-if-pr-is-approved, pre-checks]
if: ${{ needs.pre-checks.outputs.code-changed == 'true' }}
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Setup environment
id: setup-env
uses: ./.github/actions/setup
with:
cache-suffix: setup
- name: Bundle
run: |
pnpm bundle:js-api
pnpm bundle:cli
- name: Save nx cache
if: ${{ success() }}
uses: ./.github/actions/save-nx-cache
with:
cache-suffix: setup
lint:
timeout-minutes: 30
name: "Lint"
runs-on: ubuntu-latest
needs: [setup]
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Setup environment
id: setup-env
uses: ./.github/actions/setup
with:
cache-suffix: lint
full-setup: 'false'
- name: Run lint
env:
BASE_REF: ${{ github.base_ref || 'develop' }}
run: pnpm nx affected --target=lint --base=origin/$BASE_REF --head=HEAD
- name: Save nx cache
if: ${{ success() }}
uses: ./.github/actions/save-nx-cache
with:
cache-suffix: lint
trigger-build:
name: "Build Libs"
needs: [setup]
uses: ./.github/workflows/build-lib-workflow.yml
with:
base_ref: ${{ github.base_ref || 'develop' }}
build-storybook:
timeout-minutes: 30
name: "Build Storybook"
needs: [setup]
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Setup environment
id: setup-env
uses: ./.github/actions/setup
with:
cache-suffix: storybook
full-setup: 'false'
- name: Build Storybook
env:
BASE_REF: ${{ github.base_ref || 'develop' }}
run: |
pnpm nx affected --target=build-storybook --base=origin/$BASE_REF --head=HEAD --configuration=ci
- name: Save nx cache
if: ${{ success() }}
uses: ./.github/actions/save-nx-cache
with:
cache-suffix: storybook
trigger-unit-tests:
name: "Unit Tests"
needs: [setup]
uses: ./.github/workflows/unit-test-workflow.yml
with:
base_ref: ${{ github.base_ref || 'develop' }}
PR-size-check:
if: ${{ github.event_name == 'pull_request' }}
runs-on: ubuntu-latest
steps:
- name: Check PR size
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { data: pr } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: context.issue.number,
});
const additions = pr.additions;
const deletions = pr.deletions;
const totalChanges = additions + deletions;
const changedFiles = pr.changed_files;
let size = 'S';
if (totalChanges > 1000 || changedFiles > 30) size = 'XL';
else if (totalChanges > 500 || changedFiles > 20) size = 'L';
else if (totalChanges > 200 || changedFiles > 10) size = 'M';
core.summary
.addHeading('PR Size: ' + size, 3)
.addTable([
[{data: 'Metric', header: true}, {data: 'Count', header: true}],
['Files changed', String(changedFiles)],
['Additions', '+' + String(additions)],
['Deletions', '-' + String(deletions)],
['Total changes', String(totalChanges)],
]);
if (size === 'XL') {
core.summary.addRaw('⚠️ This PR is very large. Consider splitting it into smaller PRs for easier review.');
}
await core.summary.write();
if (size === 'XL') {
core.warning('This PR has ' + totalChanges + ' changes across ' + changedFiles + ' files. Consider splitting it for easier review.');
}
PR-forbidden-labels:
if: ${{ inputs.cron-run == '' || inputs.cron-run == 'false' }}
runs-on: ubuntu-latest
steps:
- name: Check for forbidden labels
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const { data: issue } = await github.rest.issues.get({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const labels = issue.labels?.map(item => item.name) || [];
const forbidden = ['next version ➡️', 'do not merge🙅🏻‍♂️'];
if (forbidden.some(l => labels.includes(l))) {
core.setFailed('The PR contains a forbidden label! You are not allowed to merge until the label is there.');
}
finalize:
if: ${{ always() }}
runs-on: ubuntu-latest
name: Final Results
needs:
[
check-if-pr-is-approved,
pre-checks,
setup,
trigger-unit-tests,
lint,
trigger-build,
build-storybook,
PR-forbidden-labels,
]
steps:
- name: Check job execution status
if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
run: exit 1
-18
View File
@@ -1,18 +0,0 @@
on:
issue_comment:
types: [created]
name: Automatic Rebase
jobs:
rebase:
name: Rebase
if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase')
runs-on: ubuntu-latest
steps:
- name: Checkout the latest code
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Automatic Rebase
uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 # 1.8
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-178
View File
@@ -1,178 +0,0 @@
name: "release"
on:
workflow_dispatch:
inputs:
dry-run-flag:
description: 'enable dry-run on artifact push'
required: false
type: boolean
default: true
push:
branches:
- develop
- develop-patch*
- master
- master-patch-*
permissions:
id-token: write # Required for OIDC
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: false
env:
GH_COMMIT: ${{ github.sha }}
GH_BUILD_NUMBER: ${{ github.run_id }}
LOG_LEVEL: "ERROR"
NODE_OPTIONS: "--max-old-space-size=5120"
jobs:
setup:
timeout-minutes: 20
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
name: "Setup"
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- uses: ./.github/actions/setup
- name: install
run: |
pnpm install --frozen-lockfile
pnpm bundle:js-api
pnpm bundle:cli
- uses: ./.github/actions/upload-node-modules-and-artifacts
release-npm:
needs: [setup]
outputs:
release_version: ${{ steps.set-version.outputs.release_version }}
timeout-minutes: 30
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC
contents: read
packages: write
actions: read
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- id: setup
uses: ./.github/actions/setup
- id: set-dryrun
uses: ./.github/actions/enable-dryrun
with:
dry-run-flag: ${{ inputs.dry-run-flag }}
- uses: ./.github/actions/download-node-modules-and-artifacts
- name: Set libraries versions
id: set-version
run: |
set -u;
./scripts/github/build/bumpversion.sh
- name: Set migrations
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
const setMigrations = require('./scripts/github/release/set-migrations.js');
setMigrations();
- name: build libraries
run: |
pnpm build:libs
pnpm build:schematics
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
name: release libraries GH registry
with:
node-version-file: '.nvmrc'
registry-url: 'https://npm.pkg.github.com'
scope: '@alfresco'
- run: pnpm run publish --tag ${{ steps.setup.outputs.npm-tag }} --provenance=false ${{ steps.set-dryrun.outputs.dryrun }}
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
name: release libraries Npm registry
with:
node-version-file: '.nvmrc'
registry-url: 'https://${{ vars.NPM_REGISTRY_ADDRESS }}'
scope: '@alfresco'
- run: pnpm run publish --tag ${{ steps.setup.outputs.npm-tag }} ${{ steps.set-dryrun.outputs.dryrun }}
create-git-tag:
runs-on: ubuntu-latest
needs: [setup, release-npm]
if: github.event_name != 'workflow_dispatch'
name: Create github tag
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 1
- uses: './.github/actions/create-git-tag'
with:
tagName: ${{ needs.release-npm.outputs.release_version }}
npm-check-bundle:
needs: [release-npm]
timeout-minutes: 15
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- uses: ./.github/actions/npm-check-bundle
push-translation-keys-to-crowdin:
name: Push translations keys to Crowdin
if: github.ref_name == 'develop' && github.event_name != 'workflow_dispatch'
runs-on: ubuntu-latest
needs: [setup]
permissions:
contents: read
packages: read
actions: read
steps:
- name: Checkout
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Push Source Files to Crowdin
uses: crowdin/github-action@e0c8f73cdc0fafde9396e056c5038217000a32d1 # v2.16.4
with:
upload_sources: true
upload_sources_args: --delete-obsolete
env:
CROWDIN_TOKEN: ${{ secrets.CROWDIN_TRANSLATIONS_TOKEN }}
pull-translation-keys-from-crowdin:
needs: push-translation-keys-to-crowdin
name: Run Crowdin pull pipeline for up-to-date sync
uses: ./.github/workflows/pull-from-crowdin.yml
secrets:
GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY: ${{ secrets.GH_APP_ENGINEERING_CONTRIB_PRIVATE_KEY }}
CROWDIN_TRANSLATIONS_TOKEN: ${{ secrets.CROWDIN_TRANSLATIONS_TOKEN }}
HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY: ${{ secrets.HXPS_GIT_COMMIT_SIGNING_PRIVATE_KEY }}
finalize:
if: always()
runs-on: ubuntu-latest
name: Final Results
needs: [release-npm, npm-check-bundle]
steps:
- name: Check job execution status
if: >-
${{
contains(needs.*.result, 'failure')
|| contains(needs.*.result, 'cancelled')
}}
run: exit 1
-14
View File
@@ -1,14 +0,0 @@
name: Stale PR Cleanup
on:
schedule:
- cron: "0 0 * * *"
workflow_dispatch:
permissions:
pull-requests: write
issues: write
jobs:
stale-pr-cleanup:
uses: Alfresco/alfresco-build-tools/.github/workflows/stale-pr-cleanup.yml@1d671f8f10336861c89c67be57c6648d98876103 # v18.19.0
@@ -1,31 +0,0 @@
name: Supply Chain Review - PR Instructions
on:
pull_request:
types: [opened, reopened, synchronize]
paths:
- "package.json"
- "pnpm-lock.yaml"
- "**/package.json"
- "pom.xml"
- "**/pom.xml"
jobs:
instructions:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: Alfresco/alfresco-build-tools/.github/actions/github-upsert-comment@1d671f8f10336861c89c67be57c6648d98876103 # v18.19.0
with:
comment-identifier: supply-chain-review-instructions
comment-body: |
## 🔒 Supply Chain Security
This PR modifies dependencies. To run a security analysis, comment:
```
/supply-chain-review
```
The analysis will check for vulnerabilities, typosquatting, maintainer takeovers, and other supply chain risks.
File diff suppressed because one or more lines are too long
-358
View File
@@ -1,358 +0,0 @@
---
on:
slash_command:
name: supply-chain-review
reaction: rocket
permissions:
contents: read
pull-requests: read
engine:
id: copilot
model: gpt-5-mini
tools:
github:
toolsets: [context, pull_requests, repos]
network:
allowed:
- defaults
- node
- java
- api.osv.dev
- api.scorecard.dev
- search.maven.org
safe-outputs:
add-comment:
hide-older-comments: true
add-labels:
allowed: [security:low, security:medium, security:high]
remove-labels:
allowed: [security:low, security:medium, security:high]
submit-pull-request-review:
source: Alfresco/alfresco-build-tools/.github/workflows/supply-chain-review.md@7479d99410acb8b63f78a5b17abb3b8ebec3a66d
---
# Supply Chain Review
You are a supply chain security analyst reviewing a pull request for dependency changes.
Your goal is to identify any dependency additions or upgrades and produce a thorough risk assessment for each change, covering known vulnerabilities, typosquatting, maintainer takeover, install script abuse, version anomalies, source code changes, and project health.
You are the primary and only analysis engine. There is no secondary check. Be thorough but calibrated: false positives erode trust, but missed threats have severe consequences.
## Step 1 — Identify Dependency Changes
Read the pull request diff and find all modified dependency files (`package.json`, `package-lock.json`, `pom.xml`, `yarn.lock`, `build.gradle`, etc.). For each changed dependency extract:
- Package name (including scope/groupId if applicable)
- Ecosystem (`npm` or `maven`)
- Old version (or mark as `NEW DEPENDENCY` if newly added)
- New version
If no dependency files were changed, post a brief PR comment stating that no dependency changes were detected and no review is needed, then stop.
## Step 1b — Filter Internal Dependencies
Before collecting external data, identify and exclude internal/private dependencies that cannot be resolved by public APIs.
**Internal dependency namespaces (skip these):**
- **Maven**: Any dependency with a `groupId` starting with `com.hyland.`, `org.alfresco.`, or `org.activiti.`
- **npm**: Any package under the `@hyland/`, `@hylandsoftware/`, or `@alfresco/` scopes
For each internal dependency found:
1. Remove it from the analysis pipeline — do NOT query OSV.dev, OpenSSF Scorecard, or registry APIs for these packages (they will fail or return irrelevant data).
2. Record the package name (with `@` replaced by `(at)` for GitHub comment compatibility), ecosystem, old version, and new version in a separate "Internal Dependencies (Skipped)" list.
3. Continue with Step 2 only for the remaining external/public dependencies.
If ALL changed dependencies are internal, skip Steps 2-4 and proceed directly to Step 5, posting a report that lists the internal dependencies and notes that no external supply chain analysis was performed.
## Step 2 — Collect Data for Each Dependency
For every changed dependency, gather the following data. Fetch all data sources in parallel where possible. If any request fails or returns no data, note it and continue — missing data alone is not proof of malice, but factor it into your confidence level.
### 2a. Known Vulnerabilities (OSV.dev)
Query the OSV.dev API for vulnerabilities affecting the **new** version:
- **npm**: `POST https://api.osv.dev/v1/query` with body `{"package":{"name":"<package-name>","ecosystem":"npm"},"version":"<new-version>"}`
- **Maven**: `POST https://api.osv.dev/v1/query` with body `{"package":{"name":"<groupId>:<artifactId>","ecosystem":"Maven"},"version":"<new-version>"}`
Record all returned vulnerability IDs, severity ratings, and summaries. CRITICAL and HIGH severity CVEs in the new version are the most urgent signal.
### 2b. OpenSSF Scorecard
Fetch the project health score. First determine the source repository from the package metadata (see 2c), then query:
`GET https://api.scorecard.dev/projects/github.com/{owner}/{repo}`
Record the overall score (0-10) and individual check results. Pay special attention to: Maintained, Code-Review, Vulnerabilities, Branch-Protection, Signed-Releases. A score below 3 is very concerning; below 5 warrants caution. If the package has no linked source repository, the scorecard will be unavailable — this is itself a risk signal.
### 2c. Package Metadata (Registry)
**For npm packages**, fetch:
`GET https://registry.npmjs.org/<package-name>`
From the full registry document, extract for BOTH the old and new versions:
- `versions[<version>]._npmUser` — the publisher
- `versions[<version>].maintainers` — the maintainer list
- `versions[<version>].scripts` — lifecycle scripts (`preinstall`, `install`, `postinstall`)
- `versions[<version>].dependencies` — runtime dependencies
- `time[<version>]` — publish timestamp
- `repository` — source repository URL
Also extract the `time` object to build a version history (last 10 versions with publish dates).
**For Maven packages**, fetch:
`GET https://central.sonatype.com/api/v1/search?q=g:<groupId>+AND+a:<artifactId>&sort=published&limit=10`
For POM details (build plugins, dependencies): `GET https://repo1.maven.org/maven2/<groupId-as-path>/<artifactId>/<version>/<artifactId>-<version>.pom`
### 2d. Source Code Diff and Release Notes
Use the PR diff itself to review the actual file changes for dependency manifest files. Additionally, if a source repository is identified (from 2c), fetch release notes and compare tags:
- Release notes: `GET https://api.github.com/repos/{owner}/{repo}/releases/tags/v<new-version>` (try with and without the `v` prefix)
- For a code-level diff between old and new versions: `GET https://api.github.com/repos/{owner}/{repo}/compare/v<old-version>...v<new-version>` (try with and without the `v` prefix)
## Step 3 — Analyze Against Threat Taxonomy
Evaluate each dependency against ALL of the following threat categories. Not every category applies to every package — use judgment.
### 3a. Known Vulnerabilities
Assess the severity and exploitability of any CVEs or advisories returned from OSV.dev. CRITICAL and HIGH severity vulnerabilities in the new version are the most urgent signal. Also check whether the upgrade itself fixes known vulnerabilities in the old version (a positive signal).
### 3b. Typosquatting / Name Confusion
Determine if the package name could be a typosquatting attempt targeting a well-known package. Consider:
- Levenshtein distance to popular packages (e.g., `lodas` vs `lodash`)
- Dash/underscore/separator swaps (e.g., `my_package` vs `my-package`)
- Suffix variants (e.g., `express-js`, `express.js`)
- Scope squatting for npm (e.g., `@attacker/lodash` vs `lodash`)
- GroupId squatting for Maven (e.g., `org.apach.commons` vs `org.apache.commons`)
Use your knowledge of the ecosystem to identify plausible targets. Reason from your training data about popular packages.
### 3c. Maintainer Takeover
Compare the publisher and maintainer metadata between the old and new versions. Red flags:
- Publisher changed between versions (different `_npmUser`)
- Old maintainers removed and replaced
- New publisher has no prior history with the package
- Classic pattern: publisher change + maintainer removal (like the event-stream incident)
### 3d. Install Script Abuse
**For npm**: Analyze lifecycle scripts (`preinstall`, `install`, `postinstall`) from the registry metadata. Red flags:
- Scripts that download and execute remote code (`curl`, `wget`, `http://`)
- `eval()`, `Function()`, `child_process` usage
- Environment variable access (`process.env`) for credential theft
- Base64/hex decoding of payloads
- Access to sensitive paths (`~/.ssh`, `~/.aws`, `~/.npmrc`, `/etc/passwd`)
- Network calls (`dns.lookup`, `net.connect`) for exfiltration
- Scripts that are NEW in this version (not present in the old version) are especially suspicious
**For Maven**: Look for dangerous build plugins in POM changes:
- `exec-maven-plugin`, `maven-antrun-plugin` with `<exec>`
- `<extensions>true</extensions>` on untrusted plugins
- Download plugins, Groovy/script plugins
### 3e. Version Anomalies
Analyze the version change pattern and history from the registry metadata:
- Major version jumps (skipping 1+ major versions)
- Version downgrade (new version < old version)
- Stable to prerelease transition
- Very recent publish (less than 48 hours old) — could indicate a rush to distribute malicious code
- Rapid successive publishes (many versions in a short window)
- Long dormancy then sudden publish (more than 1 year gap) — may indicate account takeover
### 3f. Source Code Changes
If source diffs are available (from the GitHub compare API or the PR diff itself), analyze for:
- Obfuscated code (minified without source maps, hex/unicode escapes, string concatenation to hide function names)
- Data exfiltration (network calls sending `process.env`, API keys, tokens to external endpoints)
- Filesystem access outside the package directory
- Dynamic code execution (`eval()`, `Function()`, `vm.runInNewContext`, `WebAssembly.instantiate`)
- Encoded payloads (Base64/hex decoded and executed at runtime)
- Inconsistency between release notes and actual changes (changelog says "bug fix" but diff adds network calls)
- Cryptocurrency mining patterns
- Suspicious new transitive dependencies
### 3g. Project Health
Interpret the OpenSSF Scorecard data:
- Overall score below 3/10 is very concerning
- Score below 5/10 warrants caution
- Pay attention to specific failing checks: Maintained, Code-Review, Vulnerabilities, Branch-Protection, Signed-Releases
- Missing scorecard data (no source repo linked) is itself a risk signal
### 3h. Missing Source Repository
A package with no linked source repository prevents code audit and is a risk signal, especially combined with other concerns.
### 3i. Tag Poisoning / Build Provenance
Evaluate whether the published artifact can be traced back to a verified source commit. This category covers attacks where a legitimate-looking version tag is manipulated to distribute malicious code.
#### Tag-to-Registry Provenance Mismatch
Check whether the git tag for the new version corresponds to the published artifact:
- Compare the tag commit date with the registry publish timestamp. A discrepancy of more than a few hours (allowing for CI/CD pipeline time) is suspicious.
- If the source diff between the tag and the previous tag includes changes not documented in release notes, flag as suspicious.
#### Mutable/Moved Tags
Check if the tag appears to have been recreated:
- Use `GET https://api.github.com/repos/{owner}/{repo}/git/refs/tags/{tag}` to get the tag reference.
- For annotated tags, use `GET https://api.github.com/repos/{owner}/{repo}/git/tags/{sha}` to check the tag object and its `tagger.date`.
- If the tag creation date is significantly newer than the commit it points to (e.g., more than 7 days), this may indicate the tag was deleted and recreated pointing to a different commit.
#### Unsigned Tags
Determine tag type and signing status:
- **Annotated + signed tags** (GPG or SSH signature present) — strongest integrity signal.
- **Annotated but unsigned tags** — moderate integrity; the tag is immutable but unverified.
- **Lightweight tags** — weakest integrity; easily moved without trace. Flag as a risk signal for high-profile or security-critical packages.
For the tag object, check the `verification` field in the GitHub API response for signature status.
#### Build Provenance / Attestation
Check for SLSA provenance attestations or Sigstore signatures:
**For npm packages**: Query `GET https://registry.npmjs.org/-/npm/v1/attestations/<package-name>@<new-version>`. If attestations are present, verify:
- The `predicateType` matches a known SLSA provenance type
- The `subject` digest matches the published package tarball
- The build was performed by a trusted CI system (e.g., GitHub Actions)
**For Maven packages**: Check if Sigstore `.sigstore` bundle files exist alongside the artifact at:
`GET https://repo1.maven.org/maven2/<groupId-as-path>/<artifactId>/<version>/<artifactId>-<version>.jar.sigstore`
The absence of provenance attestations on a high-profile package (>1000 weekly downloads for npm, or widely used in the ecosystem) is a moderate risk signal. Packages that previously published with provenance but stopped doing so are especially suspicious.
#### Tag Mimicry on Forks
Verify that the source repository URL in registry metadata points to the canonical repository:
- Cross-reference the `repository` field from package metadata (Step 2c) with the GitHub API response.
- If the repository URL points to a fork rather than the original project, flag as HIGH risk — this may indicate a hijacked tag on a lookalike fork.
- Check that the repository owner matches known maintainers of the package.
## Step 4 — Score and Classify Risk
Assign a risk score (0-100) to each dependency using these guidelines:
| Priority | Signal | Typical Impact |
| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- |
| Highest | Known CRITICAL/HIGH CVEs in new version, confirmed typosquatting, malicious code in diff, build provenance mismatch (tag points to different code than published artifact), tag mimicry on fork | 60+ points |
| High | Maintainer takeover pattern (publisher changed + old maintainers removed), dangerous install scripts, known compromised package, moved/recreated tag with different commit, provenance attestations removed from package that previously had them | 20-40 points |
| Medium | Low OpenSSF Scorecard (< 3), publisher changed (without full takeover), new install scripts, very recent publish (< 48h), obfuscated code in diff, unsigned lightweight tags on security-critical packages, absence of provenance on high-profile packages | 10-20 points |
| Lower | Scorecard 3-5, version anomalies, missing source repository, long dormancy, rapid publishes, tag date slightly newer than commit (within 7 days), annotated but unsigned tags | 5-10 points |
These are guidelines, not rigid formulas. Use judgment to combine signals — multiple medium signals can compound into a high-risk assessment.
**Risk level thresholds**: 0-20 = LOW, 21-50 = MEDIUM, 51-80 = HIGH, 81-100 = CRITICAL.
If no suspicious patterns are found, assign a score of 0-10 and risk level LOW. Most legitimate upgrades should score LOW.
## Step 5 — Post Findings as PR Comment
Post a structured report in the following format.
**CRITICAL: Sanitize all `@` symbols before posting**
GitHub enforces a maximum of 10 mentions per comment. Package names containing `@` (like `@hyland/core`, `@alfresco/js-api`) are interpreted as user/team mentions and trigger this limit, causing comment post failures.
**Before generating the comment text**:
1. Replace **every** `@` symbol in package names with `(at)` — e.g., `@hyland/core``(at)hyland/core`
2. Apply this transformation to ALL occurrences: table cells, headings, inline code blocks, findings sections, reason columns
3. This applies to both external and internal dependencies
4. Do NOT skip this step — even if only a few packages are affected, GitHub counts all `@` symbols
```txt
## Supply Chain Security Review
| Package | Ecosystem | Old Version | New Version | Risk Score | Risk Level |
|---------|-----------|-------------|-------------|------------|------------|
| example | npm | 1.0.0 | 2.0.0 | 5 | LOW |
### Internal Dependencies (Skipped)
| Package | Ecosystem | Old Version | New Version | Reason |
|-------------------|-----------|-------------|-------------|---------------------------------|
| (at)hyland/core | npm | 3.1.0 | 3.2.0 | Internal ((at)hyland/* scope) |
_These dependencies are internal packages not available on public registries. External API checks were skipped._
### Findings
#### `<package-name-sanitized>` (<old-version> -> <new-version>) — <RISK_LEVEL>
**Risk Score**: <score>/100
<If findings exist, list each one:>
**<Category>** (<severity>) — <title>
<detailed explanation with specific evidence>
<If no findings:>
No suspicious patterns detected. Routine upgrade.
---
### Data Collection Notes
<List any APIs that were unavailable or returned errors, so reviewers know what was and wasn't checked.>
---
### Overall Risk: <highest risk level across all dependencies>
**Recommendation**: <approve|review|block>
- **approve**: LOW risk, routine upgrade, no concerns found
- **review**: MEDIUM risk, a human should examine specific findings before merging
- **block**: HIGH/CRITICAL risk, should not be merged without security team review
```
## Step 6 — Apply Label and Review Status
- First, remove any `security:low`, `security:medium`, or `security:high` labels already present on the PR from a previous review — this PR may have been reviewed before (e.g., after a new commit), and stale risk labels must not remain alongside the new one.
- Then apply a label to the PR based on the highest risk level found:
- `security:low` for LOW risk
- `security:medium` for MEDIUM risk
- `security:high` for HIGH or CRITICAL risk
- If the highest risk level is HIGH or CRITICAL, submit a pull request review requesting changes, with a summary of the critical findings.
- If the risk is MEDIUM, submit a pull request review as a comment, noting that human review is recommended.
- If the risk is LOW, do not submit a review — the PR comment is sufficient.
## Important Guidelines
- **Never approve or merge the PR** — all actions are advisory or blocking only. A human always makes the merge decision.
- Be specific in findings — cite exact data (vulnerability ID, maintainer name, script content, file path, API response) rather than vague warnings.
- For Maven packages, adapt npm-specific checks appropriately (e.g., install scripts become build plugin analysis, maintainer metadata may be limited).
- When a package is a NEW dependency (no old version), pay extra attention to project health, name legitimacy, and install scripts since there is no historical baseline to compare against.
- If data collection fails for all external APIs, still analyze the PR diff directly and provide the best assessment you can with available information, noting the limitations clearly.
- For tag poisoning checks, not all packages will have provenance attestations — this is still an emerging practice. Weight the absence of attestations proportionally to the package's profile and criticality. Do not flag low-download utility packages for missing provenance.
- When checking tag dates, allow for reasonable CI/CD pipeline delays (up to a few hours between tag push and publish). Only flag significant discrepancies (days or weeks).
-81
View File
@@ -1,81 +0,0 @@
name: "Unit Tests Workflow"
on:
workflow_call:
inputs:
base_ref:
description: 'Base branch for affected calculation'
required: false
type: string
default: 'develop'
jobs:
generate-affected-matrix:
name: "Generate affected matrix"
runs-on: ubuntu-latest
outputs:
unitMatrix: ${{ steps.set-matrix.outputs.unitMatrix }}
hasProjects: ${{ steps.set-matrix.outputs.hasProjects }}
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: 0
- name: Setup environment
id: setup-env
uses: ./.github/actions/setup
with:
cache-suffix: test-matrix
- name: Generate affected projects matrix
id: set-matrix
env:
BASE_REF: ${{ inputs.base_ref }}
run: |
echo "Base ref is $BASE_REF"
AFFECTED_UNIT=$(pnpm nx show projects --affected --target=test --base=origin/$BASE_REF --head=HEAD --select=projects --plain --exclude=cli,stories,eslint-angular)
echo "Affected projects for UNIT: $AFFECTED_UNIT"
if [ -z "$AFFECTED_UNIT" ]; then
echo "No affected projects found"
echo "hasProjects=false" >> $GITHUB_OUTPUT
echo "unitMatrix=[]" >> $GITHUB_OUTPUT
else
UNIT_MATRIX_JSON=$(echo "$AFFECTED_UNIT" | xargs -n1 | jq -R -s -c 'split("\n") | map(select(length > 0)) | map({ "project": . })')
echo "Matrix UNIT: $UNIT_MATRIX_JSON"
echo "hasProjects=true" >> $GITHUB_OUTPUT
echo "unitMatrix=$UNIT_MATRIX_JSON" >> $GITHUB_OUTPUT
fi
- name: Save nx cache
if: ${{ success() }}
uses: ./.github/actions/save-nx-cache
with:
cache-suffix: test-matrix
unit-tests:
timeout-minutes: 30
runs-on: ubuntu-latest
needs: generate-affected-matrix
if: ${{ needs.generate-affected-matrix.outputs.hasProjects == 'true' }}
strategy:
fail-fast: false
matrix:
include: ${{ fromJson(needs.generate-affected-matrix.outputs.unitMatrix) }}
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Setup environment
id: setup-env
uses: ./.github/actions/setup
with:
cache-suffix: test-${{ matrix.project }}
full-setup: 'false'
- name: Run unit tests for ${{ matrix.project }}
env:
NODE_OPTIONS: "--max-old-space-size=5120"
run: |
xvfb-run --auto-servernum pnpm nx run ${{ matrix.project }}:test
- name: Save nx cache
if: ${{ success() }}
uses: ./.github/actions/save-nx-cache
with:
cache-suffix: test-${{ matrix.project }}
+15 -23
View File
@@ -1,26 +1,18 @@
*.log
node_modules
bundles
workspace.xml
.idea/
*.iml
.env.*
.env
dist
tmp
temp
.history
.ng_pkg_build/
coverage/
out-tsc
/reports/
e2e-result-*
licenses.txt
.DS_Store
desktop.ini
.angular
.nx
nxcache
.husky
.cursor/rules/nx-rules.mdc
.github/instructions/nx.instructions.md
lib/eslint-angular/dist/
dist/
ng2-components/coverage/
!systemjs.config.js
demo-shell-ng2/app/components/router/
ng2-components/ng2-alfresco-userinfo-old/demo/src/app/
ng2-components/ng2-alfresco-userinfo-old/src/services/bpm-user.service.spec.ts
ng2-components/ng2-alfresco-userinfo-old/src/services/ecm-user.service.spec.ts
src/environments/
/ng2-components/ng2-example-webpack/
/ng2-components/config/coverage/
*.npmrc
/demo-shell-ng2/ng2-components/
.happypack/
.happypack/
-5
View File
@@ -1,5 +0,0 @@
#!/bin/sh
export NODE_OPTIONS=--max_old_space_size=8192
lint-staged
-4
View File
@@ -1,4 +0,0 @@
{
"*.{ts,js}": ["prettier --write", "eslint"],
"*.{css,scss}": ["prettier --write", "stylelint --fix"]
}
-5
View File
@@ -1,5 +0,0 @@
# Fail on high severity vulnerabilities during audit
audit-level=high
# Use exact versions to prevent unexpected updates
save-exact=true
-1
View File
@@ -1 +0,0 @@
24.14.0
-1
View File
@@ -1 +0,0 @@
/lib/cli/scripts/resources.ts
-5
View File
@@ -1,5 +0,0 @@
{
"singleQuote": true,
"trailingComma": "none",
"printWidth": 150
}
-24
View File
@@ -1,24 +0,0 @@
import { fileURLToPath } from 'node:url';
import { dirname } from 'node:path';
import type { StorybookConfig } from '@storybook/angular';
const config: StorybookConfig = {
framework: {
name: getAbsolutePath('@storybook/angular'),
options: {}
},
staticDirs: [],
stories: ['lib/**/*.stories.ts'],
features: {
backgrounds: false
},
core: {
disableTelemetry: true
}
};
export default config;
function getAbsolutePath(value: string): any {
return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)));
}
-11
View File
@@ -1,11 +0,0 @@
import type { Preview } from '@storybook/angular';
const preview: Preview = {
parameters: {
docs: { inlineStories: true },
controls: { expanded: true }
},
tags: ['autodocs']
};
export default preview;
-10
View File
@@ -1,10 +0,0 @@
{
"extends": "../tsconfig.json",
"exclude": [
"../**/*.spec.js",
"../**/*.spec.ts",
"../**/*.spec.tsx",
"../**/*.spec.jsx"
],
"include": ["../**/*"]
}
-2
View File
@@ -1,2 +0,0 @@
_theming.scss
lib/core/src/lib/viewer/components/pdf-viewer-host.component.scss
-71
View File
@@ -1,71 +0,0 @@
{
"extends": ["stylelint-config-standard-scss"],
"rules": {
"custom-property-pattern": [
"^(mat-sys|mdc)",
{
"message": "Use only Angular Material system variables (--mat-sys-*, --mdc-*)"
}
],
"color-function-notation": "legacy",
"alpha-value-notation": "number",
"color-no-invalid-hex": true,
"function-calc-no-unspaced-operator": true,
"function-name-case": "lower",
"function-url-quotes": "always",
"function-url-scheme-disallowed-list": [
"data"
],
"length-zero-no-unit": true,
"string-no-newline": true,
"unit-no-unknown": true,
"unit-allowed-list": [
"px",
"%",
"deg",
"ms",
"em",
"vh",
"vw",
"vmin",
"s",
"rem"
],
"shorthand-property-no-redundant-values": true,
"declaration-no-important": true,
"no-duplicate-at-import-rules": true,
"declaration-block-no-duplicate-properties": [
true,
{
"ignore": [
"consecutive-duplicates-with-different-values"
]
}
],
"declaration-block-single-line-max-declarations": 1,
"declaration-property-value-disallowed-list": [
{
"/.*/": [
"initial"
]
},
{
"message": "The `initial` value is not supported in IE."
}
],
"selector-pseudo-element-colon-notation": "double",
"selector-pseudo-element-no-unknown": [true, {
"ignorePseudoElements": ["ng-deep"]
}],
"selector-type-case": "lower",
"selector-max-id": 0,
"selector-class-pattern": [
"^_?(adf|adf-|app|app-|example-|demo-|textLayer|canvasWrapper|page)",
{
"resolveNestedSelectors": true
}
],
"scss/dollar-variable-empty-line-before": null,
"scss/at-rule-conditional-no-parentheses": null
}
}
+50
View File
@@ -0,0 +1,50 @@
language: node_js
dist: trusty
sudo: false
node_js:
- "8"
before_install:
- "export DISPLAY=:99.0"
- "sh -e /etc/init.d/xvfb start"
env:
matrix:
- MODULE=ng2-components-alfresco
- MODULE=ng2-components-activiti
- MODULE=ng2-demo-shell
install:
- if ([ "$MODULE" == "ng2-components-alfresco" -o "$MODULE" == "ng2-components-activiti" ]); then
if ([ "$TRAVIS_BRANCH" = "master" ]); then
(./scripts/npm-build-all.sh || exit 1;);
else
(./scripts/npm-build-all.sh -gitjsapi development || exit 1;);
fi
fi
script:
- if ([ "$MODULE" == "ng2-components-activiti" ]); then
(./scripts/npm-build-all.sh -si -sb -t "ng2-activiti*" || exit 1;);
fi
- if ([ "$MODULE" == "ng2-components-alfresco" ]); then
(./scripts/npm-build-all.sh -si -sb -t "ng2-alfresco*" || exit 1;);
fi
- if ([ "$MODULE" == "ng2-demo-shell" ]); then
if ([ "$TRAVIS_BRANCH" = "master" ]); then
(./scripts/start.sh -t -ss || exit 1;);
else
(./scripts/start.sh -dev -t -ss -gitjsapi development || exit 1;);
fi
fi
# Send coverage data to codecov
after_success:
bash <(curl -s https://codecov.io/bash) -X gcov
cache:
directories:
- ./node_modules/material-design-lite
- ./node_modules/material-design-icons
- demo-shell-ng2/node_modules
- ng2-components/node_modules
-5
View File
@@ -1,5 +0,0 @@
{
"recommendations": [
"meterian.meterian-heidi"
]
}
+10 -30
View File
@@ -1,33 +1,13 @@
// Place your settings in this file to overwrite default and user settings.
{
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/.DS_Store": true,
"**/.happypack": true
},
"markdownlint.config": {
"MD032": false,
"MD004": false,
"MD024": false,
"MD009": false,
"MD013": false,
"MD036": false,
"MD033": false,
"MD031": false
},
"stylelint.enable": true,
"css.validate": false,
"scss.validate": false,
"stylelint.configFile": "${workspaceFolder}/.stylelintrc.json",
"stylelint.configBasedir": "${workspaceFolder}",
"stylelint.validate": [
"css",
"less",
"postcss",
"scss"
],
"editor.guides.indentation": true,
"typescript.tsdk": "node_modules/typescript/lib"
"files.exclude": {
"**/.git": true,
"**/.svn": true,
"**/.hg": true,
"**/.DS_Store": true,
"**/coverage": true,
"**/.happypack": true
},
"editor.renderIndentGuides": true,
"tslint.configFile": "ng2-components/tslint.json"
}
+48 -56
View File
@@ -1,30 +1,25 @@
# CORS solving strategies
### CORS solving strategies
A web client built with ADF typically won't be loaded from the same web server that the Alfresco Platform is running on.
This means you need to tell the Alfresco server explicitly that any request coming in from this custom web client should be allowed access
to the Content Repository. This is done by enabling
[Cross Origin Resource Sharing](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
(CORS).
The web client that we are building with the application development framework will be loaded from a different web server than the Alfresco Platform is running on.
So we need to tell the Alfresco server that any request that comes in from this custom web client should be allowed access
to the Content Repository. This is done by enabling CORS.
If you are experiencing this kind of problem, use **one of the following approaches**,
depending on your setup:
If you are experiencing this kind of problem you can follow **one of the following**:
1. [Configure Webpack Proxy](#configure-webpack-proxy)
2. [Configure angular-cli Proxy](#configure-angular-cli-proxy)
3. [Configure nginx proxy](#configure-nginx-proxy)
4. [Enable CORS in CS and PS](#configure-webpack-proxy)
## Configure Webpack Proxy
# Configure Webpack Proxy
If you are using a project created with the [Yeoman Generator](https://github.com/Alfresco/generator-ng2-alfresco-app) or the demo shell (>=1.6.0), you already have
a suitable configuration out of the box in your `config/webpack.common.js` file.
If you are using a project created with the [Yeoman Generator](https://github.com/Alfresco/generator-ng2-alfresco-app) or the demo shell >=1.6.0 you have already out of the box in your `config/webpack.common.js` the following configuration.
Say we have an app running on http://localhost:3000/ and we want all calls redirect with the following strategy:
Say we have an app running on http://localhost:3000/ and we want to redirect all calls with the following strategy:
* Content service http://localhost:8080/ redirect to -> http://localhost:3000/ecm/
* Process service http://localhost:9999/ redirect to -> http://localhost:3000/bpm/
* Content Service http://localhost:8080/ redirect to -> http://localhost:3000/ecm/
* Process Service http://localhost:9999/ redirect to -> http://localhost:3000/bpm/
Open the `config/webpack.common.js` file, find the `devServer` section and add the content:
Open the file `config/webpack.common.js` find the `devServer` section and add the content:
```javascript
devServer: {
@@ -60,21 +55,18 @@ devServer: {
```
Notes:
- With differents configuration of webpack the `devServer` properties could be in other webpack files. Search in your configuration
- With a different configuration of webpack, the `devServer` properties could be in other webpack files. Search your configuration files to find the correct location.
- If you are running the App, Content Service or Process Service on different ports change the ports accordingly in your local configuration.
- If you are runnign the App, content service or process service on different ports change the ports accordingly your local configuration.
For further details about how to configure a webpack proxy please refer to the [official documentation](https://webpack.js.org/configuration/dev-server/#devserver-proxy).
## Configure angular-cli Proxy
# Configure angular-cli Proxy
Say we have a app running on http://localhost:3000/ and we want redirect all the calls with the following strategy:
Say we have an app running on http://localhost:3000/ and we want to redirect all the calls with the following strategy:
* Content service http://localhost:8080/ redirect to -> http://localhost:3000/ecm/
* Process service http://localhost:9999/ redirect to -> http://localhost:3000/bpm/
* Content Service http://localhost:8080/ redirect to -> http://localhost:3000/ecm/
* Process Service http://localhost:9999/ redirect to -> http://localhost:3000/bpm/
Create a file next to the project's `package.json`, call it `proxy.conf.json` and add the following content:
Create a file next to projects `package.json` call it `proxy.conf.json` with the content:
```javascript
{
@@ -101,69 +93,69 @@ Create a file next to the project's `package.json`, call it `proxy.conf.json` an
}
```
Note that if you are running the App, Content Service or Process Service on different ports, you should change the ports accordingly in your local configuration.
Note if you are running the App, content service or process service on different ports change the ports accordingly your local configuration.
For further details about how to configure a webpack proxy please refer to the [official documentation](https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md).
## Configure nginx proxy
# Configure nginx proxy
### Installing nginx
## Installing nginx
Most Linux distributions will come with nginx available to install via your
package manager and on Mac OS you can use [Homebrew](http://brew.sh/).
If you want to install manually, you can follow the instructions on the
If you want to install manually however you can follow the instructions on the
[download page](http://nginx.org/en/download.html). See also the specific information for
[Windows users](http://nginx.org/en/docs/windows.html).
[windows users](http://nginx.org/en/docs/windows.html).
#### Start nginx
### Start nginx
Start nginx using the supplied configuration in [nginx.conf](nginx.conf)
nginx -c nginx.conf
#### Review nginx configuration
### Review nginx configuration
To correctly configure nginx, use the [nginx.conf](nginx.conf) file in the project root folder.
To correctly configure nginx use the following file [nginx.conf](/nginx.conf).
This will host Activiti, Alfresco and the app dev framework under the same origin.
* ECM : http://localhost:8888/alfresco/
* BPM : http://localhost:8888/activiti/
To make everything work, you should change the address of ECM and BPM. In the demo app you can do that by clicking on the top right settings menu and changing the bottom left options: *ECM host* and *BPM host*.
To make everything work, you have to change the address of the ECM and BPM. In the demo app you can do that clicking on the top right settings menu and change the bottom left options: *ECM host* and *BPM host*.
This configuration assumes a few things:
This configuration assumes few things:
* Port mapping:
* nginx entry point: 0.0.0.0:8888
* Demo Shell: localhost:3000
* Alfresco: localhost:8080
* Activiti: localhost:9999
* Demo Shell: locathost:3000
* Alfresco: locathost:8080
* Activiti: locathost:9999
You can modify all these values at their respective `location` directive in the
[nginx.conf](/nginx.conf) file.
All those values can be modified at their respective `location` directive on the [nginx.conf](/nginx.conf) file.
See the [Alfresco community page](https://community.alfresco.com/community/application-development-framework/blog/2016/09/28/adf-development-set-up-with-nginx-proxy) about using nginx with ADF for further information.
If you want to know more on how to install and configure nginx to work with the Application Development Framework can be found [here](https://community.alfresco.com/community/application-development-framework/blog/2016/09/28/adf-development-set-up-with-nginx-proxy)
## Enable CORS in CS and PS
If you want to completely enable CORS calls in your Content Services and Process Services,
please refer to the following Alfresco documents:
# Enable CORS in CS and PS
* [Enable Cross Origin Resource Sharing (CORS) in Alfresco Process Services](https://support.hyland.com/r/Alfresco/Alfresco-Process-Services/24.4/Alfresco-Process-Services/Configure/Overview/CORS)
If you want completely enable CORS call on your Content service and Process service, plese refer to the following alfresco documents:
* [Enable Cross Origin Resource Sharing (CORS) in Alfresco Process Services](http://docs.alfresco.com/process-services1.6/topics/enabling-cors.html)
* Enable Cross Origin Resource Sharing (CORS) in Alfresco Content Services
The easiest approach is to add the [enablecors](https://artifacts.alfresco.com/nexus/service/local/repositories/releases/content/org/alfresco/enablecors/1.0/enablecors-1.0.jar)
platform module JAR to the `$ALF_INSTALL_DIR/modules/platform` directory and restart the server.
This is the easiest way, add the [enablecors](https://artifacts.alfresco.com/nexus/service/local/repositories/releases/content/org/alfresco/enablecors/1.0/enablecors-1.0.jar)
platform module JAR to the *$ALF_INSTALL_DIR/modules/platform* directory and restart the server.
Note that, by default, the CORS filter that is enabled will allow any origin.
Note. by default the CORS filter that is enabled will allow any origin.
##Or - Manually update the web.xml file
Alternatively, you can update the `web.xml` file manually.
Modify `$ALF_INSTALL_DIR/tomcat/webapps/alfresco/WEB-INF/web.xml` and uncomment the following section and update
Modify *$ALF_INSTALL_DIR/tomcat/webapps/alfresco/WEB-INF/web.xml* and uncomment the following section and update
`cors.allowOrigin` to `http://localhost:3000`:
```xml
```
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
@@ -197,11 +189,11 @@ Modify `$ALF_INSTALL_DIR/tomcat/webapps/alfresco/WEB-INF/web.xml` and uncomment
</init-param>
</filter>
```
When specifying the `cors.allowOrigin` URL, make sure that you use the URL that will be used by the web client.
When specifying the `cors.allowOrigin` URL make sure to use the URL that will be used by the web client.
Then uncomment the filter mappings:
Then uncomment filter mappings:
```xml
```
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/api/*</url-pattern>
+55
View File
@@ -0,0 +1,55 @@
# Browser Support
Browser support and polyfills guide.
Browser compatibility and support depends on targeted browsers and 3rd party libraries. ADF framework is based on the following libraries and components:
- Angular 2 (all ADF components)
- Material Design Lite (all ADF components)
- Moment.js (many ADF components)
- PDF.js (`ng2-alfresco-viewer` component)
- Raphael.js (`ng2-alfresco-diagrams`, `ng2-alfresco-analytics`)
- Chart.js (`ng2-alfresco-analytics`)
- Material Design - Date and Time Picker (`ng2-activiti-form`, `ng2-alfresco-analytics`)
## Browser polyfills
### Angular 2
Please refer to the [official guide](https://angular.io/docs/ts/latest/guide/browser-support.html) for Angular 2 browser support.
ADF (demo shell) imports by default the following set of recommended polyfills:
- [core-js](https://www.npmjs.com/package/core-js) (ES6 standard support)
### 3rd party libraries
Please refer to the following list of [popular polyfills](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills) for HTML5 cross-browser compatibility.
ADF (demo shell) imports by default the following set of recommended polyfills:
- [intl](https://www.npmjs.com/package/intl), Polyfill the ECMA-402 Intl API (except collation), **IE**/**Safari**
- [dom4](https://github.com/WebReflection/dom4), A fully tested and covered polyfill for new DOM Level 4 entries, **IE**
- [element.scrollintoviewifneeded-polyfill](https://www.npmjs.com/package/element.scrollintoviewifneeded-polyfill), simple JavaScript implementation of the non-standard WebKit method scrollIntoViewIfNeeded that can be called on DOM elements, **IE**/**Firefox**/**Safari**, required only to support **Material Design - Date and Time Picker** component
- [pdfjs compatibility](https://www.npmjs.com/package/pdfjs-dist), Portable Document Format (PDF) library that is built with HTML5, **IE**
- (dialog-polyfill)[https://www.npmjs.com/package/dialog-polyfill], Polyfill for the dialog element, **IE**/**Safari**/**Firefox**
## Example
```html
<!-- Polyfill(s) for Safari (pre-10.x) -->
<script src="node_modules/intl/dist/Intl.min.js"></script>
<script src="node_modules/intl/locale-data/jsonp/en.js"></script>
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/dom4/1.8.3/dom4.js"></script>
<script src="node_modules/element.scrollintoviewifneeded-polyfill/index.js"></script>
<!-- Polyfill(s) for pdf support -->
<script src="node_modules/pdfjs-dist/web/compatibility.js"></script>
<!-- Polyfill(s) for dialogs -->
<script src="node_modules/dialog-polyfill/dialog-polyfill.js"></script>
<link rel="stylesheet" type="text/css" href="node_modules/dialog-polyfill/dialog-polyfill.css" />
```
For a complete code please refer to [demo shell](demo-shell-ng2/index.html) example.
-23
View File
@@ -1,23 +0,0 @@
# Contributor Code of Conduct
We want to make everyone feel welcome to contribute to ADF.
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)
-78
View File
@@ -1,78 +0,0 @@
# Contributing to ADF
- [Library Contents](#submitting-a-pull-request-pr)
- [Code style](#code-style)
- [Test guide](#test-guide)
## Submitting a Pull Request (PR)
Before you submit a pull request please follow the steps below:
* Search in [GitHub PR](https://github.com/Alfresco/alfresco-ng2-components/pulls) for an open or closed PR
that could solve or already solves your issue.
* Search in the [GitHub release history](https://github.com/Alfresco/alfresco-ng2-components/releases) to see if your
issue has already been solved in a new version of ADF.
* Fork our repository (if you don't know how to do this, read [this GitHub document](https://help.github.com/articles/creating-a-pull-request-from-a-fork/)).
* Make your changes in a new git branch starting from develop and following our [naming convention](https://github.com/Alfresco/alfresco-ng2-components/wiki/Branching-Strategy)
```shell
git checkout -b dev-{developerName}-{GitIssuedId/JiraIssueId} develop
```
* Create your PR **including appropriate test cases** following the [code contribution acceptance criteria](https://github.com/Alfresco/alfresco-ng2-components/wiki/Code-contribution-acceptance-criteria)
* Run the tests and make sure they are green. Please don't comment out or exclude the tests that are already in place.
* Commit your change using the [commit format message good practice](https://github.com/Alfresco/alfresco-ng2-components/wiki/Commit-format)
* Push your branch to GitHub:
```shell
git push origin dev-{developerName}-{GitIssuedId/JiraIssueId}
```
* In GitHub, send a pull request to `develop`.
* If we suggest changes then:
* Make the required updates.
* Re-run the tests.
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
```shell
git fetch develop
git checkout dev-my-branch
git rebase develop -i
git push -f
```
Note: If you need more information about how to sync your fork, see [this page](https://help.github.com/articles/syncing-a-fork/).
## Code style
The code style for ADF follows the [Angular style guide](https://angular.io/guide/styleguide) plus some internal rules.
The codebase is also checked with:
- ESLint tool
- Stylelint tool
## Test guide
In ADF, we encourage the use of behavior-driven development (BDD).
### General guidelines
* Class selector in all the tests is not suggested. Use of the element ID is preferred
* Any test case should test only one behavior
* Use of the Angular [testBed](https://angular.io/guide/testing#testbed) is highly recommended
### File name
* The file name specification must be the same as the component/service/pipe it tests plus the .spec. suffix.
* The specification file must be in the same folder as the component/service/pipe it tests.
### Describer Name
* The Main describer of the test should be the name of the class under test
* The sub describe is used for grouping related behavior test. Do not overuse it.
### Test Name
Any test should follow the naming convention:
[Should] [ ***Expected Behavior*** ] [when/after/before] [ ***State Under Test*** ].
+41
View File
@@ -0,0 +1,41 @@
# Introduction to the Alfresco Application Development Framework
The Alfresco application development framework is based on the [Angular 2 JavaScript library](https://angular.io/).
The framework is provided by Alfresco to make it easy to build custom web applications that
should manage and view content in the [Alfresco Platform Repository](http://docs.alfresco.com/5.1/concepts/content-repo-about.html) in a custom way.
As you probably know, there is a general user interface called [Alfresco Share](http://docs.alfresco.com/5.1/concepts/gs-intro.html) available out-of-the-box.
Share is usually used as a quick way of getting started with content management with Alfresco. It gives you access to pretty much all
the features provided by the Alfresco ECM system. And a lot of customers customize it for their specific domain.
However, there are use-cases that Share does not fit very well, such as:
- Feature-based clients, exposing functionality to perform a specific task(s)
- Role-based clients, exposing functionality based on role
- Clients where the UI layout and style differs significantly from the Share layout and styling
- [Mashup clients](http://whatis.techtarget.com/definition/mash-up)
This is where this application development framework comes into play, it can be used to create exactly the user interface
(i.e. web client) that the requirements demand.
The framework consists of a number of components that can be combined together to form a customized content management application.
Here is a list of some of the available web components:
- [Core library](ng2-components/ng2-alfresco-core/README.md)
- [DataTable](ng2-components/ng2-alfresco-datatable/README.md)
- [DocumentList](ng2-components/ng2-alfresco-documentlist/README.md)
- [Viewer](ng2-components/ng2-alfresco-viewer/README.md)
- [Login](ng2-components/ng2-alfresco-login/README.md)
- [Upload](ng2-components/ng2-alfresco-upload/README.md)
You can browse all the components at this [page](http://devproducts.alfresco.com/).
An architecture overview looks like this:
<p align="center">
<img title="alfresco-ng2-components-architecture" alt='alfresco' src='assets/alfresco-app-dev-framework-architecture.png'></img>
</p>
Here we can also see that there is an Alfresco JavaScript framework in use that wraps the Alfresco REST API. To make things easier for the client developer.
+27
View File
@@ -0,0 +1,27 @@
# Prerequisites for building and running apps with the Alfresco Application Development Framework
The [Angular 2](https://angular.io/) based application development framework requires the following:
- An Alfresco Platform Repository (version [201609 Early Access](https://community.alfresco.com/docs/DOC-6372-alfresco-community-edition-file-list-201609-ea) or newer)
- [Download and install Activiti](https://www.alfresco.com/products/bpm/alfresco-activiti/trial)
- [Node.js](https://nodejs.org/en/) JavaScript runtime.
- [npm](https://www.npmjs.com/) package manager for JavaScript.
- (If you use ECM and BPM together) Make sure your user has the same username and password in both system
- [If you are experiencing CORS problem read this guide](/ALFRESCOCORS.md)
*Note: Default username for activiti is "admin@app.activiti.com" and "admin" for Alfresco, and also the default password are different. Change them to be equal.*
**Verify that you are running at least node `v5.x.x` and npm `3.x.x`**
by running `node -v` and `npm -v` in a terminal/console window.
Older versions produce errors.
## Installing Node.js
If you don't have Node.js installed then access this [page](https://nodejs.org/en/download/) and use the appropriate installer for your OS.
Make sure the Node.js version is > 5:
```
$ node -v
v5.12.0
```
+74 -56
View File
@@ -1,72 +1,90 @@
# Alfresco Application Development Framework (ADF)
# ALFRESCO ANGULAR COMPONENTS
[![Join the chat at https://gitter.im/Alfresco/alfresco-ng2-components](https://badges.gitter.im/Alfresco/alfresco-ng2-components.svg)](https://gitter.im/Alfresco/alfresco-ng2-components?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
<p>
<a title='Build Status Travis' href="https://travis-ci.org/Alfresco/alfresco-ng2-components">
<img src='https://travis-ci.org/Alfresco/alfresco-ng2-components.svg?branch=master' alt='travis
Status' />
</a>
<a title='Build Status AppVeyor' href="https://ci.appveyor.com/project/alfresco/alfresco-ng2-components">
<img src='https://ci.appveyor.com/api/projects/status/github/Alfresco/alfresco-ng2-components' alt='travis
Status' />
</a>
<a href='https://codecov.io/gh/Alfresco/alfresco-ng2-components'>
<img src='http://img.shields.io/codecov/c/github/Alfresco/alfresco-ng2-components/master.svg?maxAge=2592000' alt='Coverage Status' />
</a>
<a href='https://github.com/Alfresco/alfresco-ng2-components/blob/master/LICENSE'>
<img src='https://img.shields.io/hexpm/l/plug.svg' alt='license' />
</a>
</p>
## Introduction
See the [introduction page](docs/user-guide/adf-introduction.md) in our
[documentation](docs/README.md) for an overview of ADF along with links
to useful starting points.
See the following [page](INTRODUCTION.md) for an introduction to the Alfresco Application Development Framework.
## Prerequisites
```text
Node: 18.x
NPM: 9.x
```
Also, check out the tutorial: [Creating your first ADF Application](docs/tutorials/creating-your-first-adf-application.md)
for full details on what you may need to install before using ADF.
### See also
- [Node Version Manager](docs/tutorials/nvm.md)
- [CORS guide](ALFRESCOCORS.md)
## Installation
This project uses **pnpm** for package management with built-in supply chain attack protection.
```bash
pnpm install # install all packages
pnpm run add <package> # add a new package (with security check)
```
### Supply Chain Security
**Layer 1: pnpm script blocking**
- All lifecycle scripts (postinstall, etc.) are blocked by default
- Only trusted packages in `pnpm-workspace.yaml` can run scripts
- Protects during `pnpm install` and `pnpm add`
**Layer 2: Security database check**
- `pnpm run add` checks packages against OSV and GitHub Advisory databases BEFORE installing
- Pre-commit hook blocks commits containing known malicious packages
**Layer 3: npm blocked**
- Running `npm install` will fail - enforces pnpm usage
Before you start using this development framework, make sure you have installed all required software and done all the
necessary configuration, see this [page](PREREQUISITES.md).
## Components
You can find the sources for all ADF components in the [`lib`](/lib) folder.
To view the complete list of all the components that you can use to build your custom Alfresco (ECM,BPM) client follow this link:
[Components](/ng2-components).
## Libraries
You can browse all the components at the following [page](http://devproducts.alfresco.com/).
ADF Libraries list:
## Demo Application
- [Content services](https://github.com/Alfresco/alfresco-ng2-components/tree/develop/lib/content-services)
- [Core](https://github.com/Alfresco/alfresco-ng2-components/tree/develop/lib/core)
- [Extensions](https://github.com/Alfresco/alfresco-ng2-components/tree/develop/lib/extensions)
- [Insights](https://github.com/Alfresco/alfresco-ng2-components/tree/develop/lib/insights)
- [Process Service Cloud](https://github.com/Alfresco/alfresco-ng2-components/tree/develop/lib/process-services-cloud)
- [Process service](https://github.com/Alfresco/alfresco-ng2-components/tree/develop/lib/process-services)
- [Stories](https://github.com/Alfresco/alfresco-ng2-components/tree/develop/lib/stories)
A separate application showcasing integration of components can be found [here](https://github.com/Alfresco/alfresco-ng2-components/tree/master/demo-shell-ng2).
You will find examples of basic interaction for both BPM and ECM sets of widgets.
## Yeoman generators
To speed up the development of your Alfresco Angular 2 application, or Alfresco Angular 2 component, use one of the Yeoman generators.
These generators will create a full working project with all the right libraries and tools.
<p align="center">
<img title="yeoman generator" src='https://github.com/yeoman/media/blob/master/optimized/yeoman-150x150-opaque.png' alt='yeoman logo' />
</p>
### Generate an Alfresco web component starter project
To generate your Alfresco Angular 2 component you can use the following Yeoman generator:
- [Yeoman Generator Angular 2 Alfresco component](https://github.com/Alfresco/generator-ng2-alfresco-component)
### Generate an Alfresco web application starter project
To generate your Alfresco Angular 2 application you can use the following Yeoman generator:
- [Yeoman Generator Angular 2 Alfresco application](https://github.com/Alfresco/generator-ng2-alfresco-app)
## Amazon AWS Elastic Beanstalk fast deploy
<p align="center">
<img alt="AmazonWebservices Logo.svg" src="https://upload.wikimedia.org/wikipedia/commons/1/1d/AmazonWebservices_Logo.svg" width="250" height="94">
</p>
To deploy directly on your AWS instance our demo shell click the button below:
<a title="Deploy to AWS" href="https://console.aws.amazon.com/elasticbeanstalk/home?region=us-west-2#/newApplication?applicationName=Alfresco&solutionStackName=Node.js&tierName=WebServer&sourceBundleUrl=https://s3-us-west-2.amazonaws.com/elasticbeanstalk-us-west-2-677901592050/ADF_1.0.zip" target="_blank"><img src="http://d0.awsstatic.com/product-marketing/Elastic%20Beanstalk/deploy-to-aws.png" height="40"></a>
## Browser Support
All components are supported in the following browsers:
| **Browser** | **Version** |
|-------------|-------------|
| Chrome | Latest |
| Safari | Latest |
| Firefox | Latest |
| Edge | Latest |
|**Browser** |**Version** |
|--- |--- |
|Chrome |Latest |
|Safari (OS X) |9.x |
|Firefox* |Latest |
|Edge |13, 14 |
|Internet Explorer |11 |
* Due to a [Firefox known issue](https://bugzilla.mozilla.org/show_bug.cgi?id=1188880), the Alfresco Upload Component does not currently support folder upload functionality on Firefox.
Please refer to the [Browser Support](BROWSER-SUPPORT.md) article for more details.
+41
View File
@@ -0,0 +1,41 @@
# Test against this version of Node.js
branches:
only:
- master
- development
- dev-build-test
environment:
nodejs_version: "8"
matrix:
- COMPONENT_NAME: ng2-components-activiti
- COMPONENT_NAME: ng2-components-alfresco
- COMPONENT_NAME: ng2-demo-shell
# Install scripts. (runs after repo cloning)
install:
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version
# install module
- if %COMPONENT_NAME% EQU ng2-components-activiti (
if %APPVEYOR_REPO_BRANCH EQU master
(cd scripts && sh npm-build-all.sh -t "ng2-activiti*" || exit 1)
else
(cd scripts && sh npm-build-all.sh -t "ng2-activiti*" -gitjsapi development|| exit 1)
)
- if %COMPONENT_NAME% EQU ng2-components-alfresco (
if %APPVEYOR_REPO_BRANCH EQU master
(cd scripts && sh npm-build-all.sh -t "ng2-alfresco*" || exit 1)
else
(cd scripts && sh npm-build-all.sh -t "ng2-alfresco*" -gitjsapi development|| exit 1)
)
- if %COMPONENT_NAME% EQU ng2-demo-shell (
if %APPVEYOR_REPO_BRANCH EQU master
(cd scripts && sh start.sh -t -ss || exit 1)
else
(cd scripts && sh start.sh -dev -t -ss -gitjsapi development|| exit 1)
)
# Don't actually build.
build: off
Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

-13
View File
@@ -1,13 +0,0 @@
"project_id": "11"
"api_token_env": "CROWDIN_TOKEN"
"base_path": "."
"base_url": "https://hyland.api.crowdin.com"
"preserve_hierarchy": true
"files": [
{
"source": "/**/**/i18n/en.json",
"translation": "/%original_path%/%two_letters_code%.%file_extension%",
"export_only_approved": "true",
"update_option": "update_without_changes"
}
]
-166
View File
@@ -1,166 +0,0 @@
{
"version": "0.2",
"language": "en",
"words": [
"activiti",
"adhoc",
"afts",
"appkey",
"Arial",
"arrowdown",
"arrowup",
"auditable",
"AUTHTYPE",
"backend",
"baseitem",
"BASESHAREURL",
"berseria",
"booleanvisibility",
"booleanvisibilityprocess",
"boolitem",
"BPMECM",
"BPMHOST",
"cardview",
"checkboxes",
"classlist",
"Collapsable",
"CONTEXTROOTBPM",
"CONTEXTROOTECM",
"cryptodoc",
"CSRF",
"datacolumn",
"datarow",
"Datasource",
"datatable",
"dateitem",
"datepicker",
"datetimeitem",
"Datetimepicker",
"dbpci",
"DDTHH",
"devops",
"devtools",
"dialpad",
"DISABLECSRF",
"doclib",
"docx",
"dropdownrestprocess",
"Droppable",
"dryrun",
"ECMBPM",
"ECMHOST",
"edjs",
"Examinate",
"exif",
"filedata",
"filelink",
"filesize",
"firstname",
"floatitem",
"folderlink",
"formtotestvalidations",
"fullname",
"fullscreen",
"gitter",
"glyphicon",
"gridster",
"hardend",
"highlightable",
"hotfix",
"Hyland",
"imgpreview",
"Inplace",
"intitem",
"jira",
"jsons",
"jwks",
"keycodes",
"keyvaluepairs",
"keyvaluepairsitem",
"lastname",
"listgrid",
"mapitem",
"mimetype",
"mincount",
"minlength",
"minmax",
"MLTEXT",
"mousedrag",
"mouseenter",
"multiselect",
"mysites",
"numbervisibilityprocess",
"OAUTHCONFIG",
"oidc",
"overridable",
"pdfjs",
"penta",
"printf",
"processparent",
"processstring",
"processwithstarteventform",
"processwithvariables",
"Promise",
"promisify",
"qshare",
"quicktime",
"repo",
"requirednumbervisibility",
"rowspan",
"selectitem",
"sharedlinks",
"sidenav",
"snackbar",
"SOLR",
"starteventform",
"subfolders",
"swimlanes",
"swsdp",
"tabindex",
"taggable",
"tasklist",
"textitem",
"Theming",
"transcluded",
"transclusion",
"triggerable",
"truthy",
"typeahead",
"typeahed",
"uncheck",
"Unclaim",
"Undeployed",
"unfavorite",
"unlisten",
"unshare",
"UPDATEPERMISSIONS",
"uploader",
"uploadfileform",
"userinfo",
"validatable",
"validators",
"waypoint",
"waypoints",
"webm",
"Whitespaces",
"xdescribe",
"xsrf",
"zestiria",
"webscript"
],
"dictionaries": [
"html",
"en-gb",
"en_US",
"softwareTerms",
"node"
],
"ignorePaths": [
"lib/{content-services,core,extensions,insights,process-services}/**/*.spec.ts",
"lib/{content-services,core,extensions,insights,process-services}/**/*.mock.ts",
"**/*.stories.ts"
],
"ignoreRegExpList": [
"(\"|'|`)((?:\\\\1|(?:(?!\\1).))*)\\1"
]
}
@@ -0,0 +1,18 @@
files:
"/opt/elasticbeanstalk/hooks/appdeploy/pre/50npm.sh" :
mode: "000775"
owner: root
group: root
content: |
#!/bin/bash
function error_exit
{
eventHelper.py --msg "$1" --severity ERROR
exit $2
}
export HOME=/home/ec2-user
echo "export home"
sudo curl -sL https://rpm.nodesource.com/setup_6.x | sudo -E bash -
sudo yum install -y nodejs
+19
View File
@@ -0,0 +1,19 @@
# http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[package.json]
indent_style = space
indent_size = 2
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false
+17
View File
@@ -0,0 +1,17 @@
typings/
node_modules/
bower_components/
ng2-components/
app/**/*.js
app/**/*.js.map
app/**/*.d.ts
!app/js/Polyline.js
.idea
versions.json
dist/
coverage/
# docker files
docker-compose.yml
Dockerfile
+101
View File
@@ -0,0 +1,101 @@
# ADF Demo Application
Please note that this application is not an official product, but a testing and demo application to showcase complex interactions for ADF components.
## Installing
To correctly use this demo check that on your machine is running [Node](https://nodejs.org/en/) version 5.x.x or higher.
```sh
git clone https://github.com/Alfresco/alfresco-ng2-components.git
cd alfresco-ng2-components/demo-shell-ng2/
npm install
```
## Proxy settings and CORS
To simplify development and reduce the time to get started the application features the following Proxy settings:
- **http://localhost:3000/ecm** is mapped to **http://localhost:8080**
- **http://localhost:3000/bpm** is mapped to **http://localhost:9999**
The settings above address most common scenarios for running ACS on port 8080 and APS on port 9999 and allow you to skip the CORS configuration.
If you would like to change default proxy settings, please edit the `config/webpack.common.js` file.
## Application settings (server-side)
All server-side application settings are stored in the `app.config-dev.json` and `app.config-prod.json` files.
By default the configuration files have the content similar to the following one:
```json
{
"ecmHost": "http://localhost:3000/ecm",
"bpmHost": "http://localhost:3000/bpm",
"application": {
"name": "Alfresco"
}
}
```
You can add any additional settings to the application configuration file if needed.
Configuration files are picked based on environment settings (see `app.module.ts` for more details).
```ts
let appConfigFile = 'app.config-dev.json';
if (process.env.ENV === 'production') {
appConfigFile = 'app.config-prod.json';
}
@NgModule({
imports: [
...
CoreModule.forRoot({
appConfigFile: appConfigFile
}),
...
]
})
```
## Development build
```sh
npm start
```
This command compiles and starts the project in watch mode.
Browser will automatically reload upon changes.
Upon start you can navigate to `http://localhost:3000` with your preferred browser.
### Important notes
This script is recommended for development environment and not suited for headless servers and network access.
## Production build
```sh
npm run build
npm run start:dist
```
This command builds project in `production` mode.
All output is placed to `dist` folder and can be served your preferred web server.
You should need no additional files outside the `dist` folder.
### Important notes
By default demo application is configured to use [wsrv](https://www.npmjs.com/package/wsrv) tool (lightweight web server)
to serve production build output. It will be running at `0.0.0.0` address with port `3000` and allow you accessing your application
via network. However you can use any web server of your choice in production.
## Development branch build
If you want to run the demo shell with the latest change from the development branch, use the following command from the /script folder:
```sh
./npm-clean.sh
./start-linked.sh -install
```
+7
View File
@@ -0,0 +1,7 @@
{
"ecmHost": "http://localhost:3000/ecm",
"bpmHost": "http://localhost:3000/bpm",
"application": {
"name": "Alfresco"
}
}
+7
View File
@@ -0,0 +1,7 @@
{
"ecmHost": "http://localhost:3000/ecm",
"bpmHost": "http://localhost:3000/bpm",
"application": {
"name": "Alfresco"
}
}
+77
View File
@@ -0,0 +1,77 @@
var port = process.env.PORT || 3000,
http = require('http'),
fs = require('fs'),
url = require('url'),
mime = require('mime'),
html = fs.readFileSync('index.html');
var log = function(entry) {
fs.appendFileSync('/tmp/sample-app.log', new Date().toISOString() + ' - ' + entry + '\n');
};
var server = http.createServer(function (req, res) {
// Parse the request containing file name
var pathname = url.parse(req.url).pathname;
// Print the name of the file for which request is made.
console.log("Request for " + pathname + " received.");
if (req.method === 'POST') {
var body = '';
req.on('data', function(chunk) {
body += chunk;
});
req.on('end', function() {
if (req.url === '/') {
log('Received message: ' + body);
} else if (req.url = '/scheduled') {
log('Received task ' + req.headers['x-aws-sqsd-taskname'] + ' scheduled at ' + req.headers['x-aws-sqsd-scheduled-at']);
}
res.writeHead(200, 'OK', {'Content-Type': 'text/plain'});
res.end();
});
} else {
var filename = pathname.substr(1);
if(filename === '' || filename.indexOf('.') === -1){
filename = 'index.html';
}
// Read the requested file content from file system
fs.readFile(filename, function (err, data) {
if (err) {
console.log(err, filename);
// HTTP Status: 404 : NOT FOUND
// Content Type: text/plain
res.writeHead(404, {'Content-Type': 'text/html'});
}else{
//Page found
// HTTP Status: 200 : OK
// Content Type: text/plain
var type = mime.lookup(filename);
console.log('type',type);
if (!res.getHeader('content-type')) {
var charset = mime.charsets.lookup(type);
res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''));
}
if(type.indexOf('image') > -1 || type.indexOf('font') > -1){
var img = fs.readFileSync(pathname.substr(1));
res.end(img, 'binary');
}else{
res.write(data.toString());
}
// Write the content of the file to response body
}
// Send the response body
res.end();
});
}
});
// Listen on port 3000, IP defaults to 127.0.0.1
server.listen(port);
// Put a friendly message on the terminal
console.log('Server running at http://127.0.0.1:' + port + '/');
+35
View File
@@ -0,0 +1,35 @@
@media screen and (max-width: 1024px) {
.mdl-layout__header {
display: block;
}
}
@media screen and (max-width: 1024px) {
.mdl-layout__header {
display: block;
}
}
.mdl-layout-title {
font-size: 17px;
}
.user-profile {
margin-right: 10px;
}
.mdl-button-padding {
padding-left: 20px;
}
.hide {
display: none !important;
}
.mdl-navigation__link {
cursor: pointer;
}
.mdl-navigation__link label {
cursor: pointer;
}
+73
View File
@@ -0,0 +1,73 @@
<!-- Always shows a header, even in smaller screens. -->
<div mdl class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header main_header_adf" [ngClass]="{hide: isAPageWithHeaderBar()}">
<div class="mdl-button-padding mdl-layout__header-row">
<!-- User Info -->
<ng2-alfresco-userinfo class="user-profile" [menuOpenType]="left">
</ng2-alfresco-userinfo>
<!-- Title -->
<span class="mdl-layout-title">Demo Application</span>
<!-- Add spacer, to align navigation to the right -->
<div class="mdl-layout-spacer"></div>
<!-- Search bar -->
<search-bar (expand)="onToggleSearch($event)"></search-bar>
<!-- Navigation. We hide it in small screens. -->
<nav class="mdl-navigation mdl-layout--large-screen-only">
<a class="mdl-navigation__link" data-automation-id="home" href="" routerLink="/">Home</a>
<a class="mdl-navigation__link" data-automation-id="files" href="" routerLink="/files">DocumentList</a>
<a class="mdl-navigation__link" data-automation-id="activiti" href="" routerLink="/activiti">Process Services</a>
<a class="mdl-navigation__link" data-automation-id="form" href="" routerLink="/form">Form</a>
<a class="mdl-navigation__link" data-automation-id="login" href="" routerLink="/login">Login</a>
<a class="mdl-navigation__link" data-automation-id="settings" href="" routerLink="/settings">Settings</a>
</nav>
</div>
</header>
<div class="mdl-layout__drawer">
<nav class="mdl-navigation">
<a class="mdl-navigation__link" (click)="onLogout($event)">
<label tabindex="0">Logout</label>
</a>
</nav>
<span class="mdl-layout-title">Languages</span>
<nav class="mdl-navigation">
<a class="mdl-navigation__link" (click)="changeLanguage('en')">
<span class="adf-flag-icon adf-flag-icon-gb"></span>
<label tabindex="0"> English</label>
</a>
<a class="mdl-navigation__link" (click)="changeLanguage('it')">
<span class="adf-flag-icon adf-flag-icon-it"></span>
<label tabindex="0"> Italian</label>
</a>
<a class="mdl-navigation__link" (click)="changeLanguage('ru')">
<span class="adf-flag-icon adf-flag-icon-ru"></span>
<label tabindex="0"> Russian</label>
</a>
</nav>
<span class="mdl-layout-title">Components</span>
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="" routerLink="/" (click)="hideDrawer()">Home</a>
<a class="mdl-navigation__link" href="" routerLink="/files" (click)="hideDrawer()">DocumentList</a>
<a class="mdl-navigation__link" href="" routerLink="/datatable" (click)="hideDrawer()">DataTable</a>
<a class="mdl-navigation__link" href="" routerLink="/uploader" (click)="hideDrawer()">Uploader</a>
<a class="mdl-navigation__link" href="" routerLink="/login" (click)="hideDrawer()">Login</a>
<a class="mdl-navigation__link" href="" routerLink="/activiti" (click)="hideDrawer()">Process Services</a>
<a class="mdl-navigation__link" href="" routerLink="/webscript" (click)="hideDrawer()">Webscript</a>
<a class="mdl-navigation__link" href="" routerLink="/tag" (click)="hideDrawer()">Tag</a>
<a class="mdl-navigation__link" href="" routerLink="/social" (click)="hideDrawer()">Social</a>
<a class="mdl-navigation__link" href="" routerLink="/about" (click)="hideDrawer()">About</a>
<a class="mdl-navigation__link" href="" routerLink="/settings" (click)="hideDrawer()">Settings</a>
</nav>
</div>
<main class="mdl-layout__content" (dragover)="onDragOverMainPage($event)"
(drop)="onDragOverMainPage($event)">
<div class="page-content">
<router-outlet></router-outlet>
</div>
</main>
</div>
+108
View File
@@ -0,0 +1,108 @@
/*!
* @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 { Component } from '@angular/core';
import { Router } from '@angular/router';
import {
AlfrescoTranslationService,
AlfrescoAuthenticationService,
AlfrescoSettingsService,
StorageService,
LogService
} from 'ng2-alfresco-core';
declare var document: any;
@Component({
selector: 'alfresco-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
searchTerm: string = '';
constructor(private authService: AlfrescoAuthenticationService,
private router: Router,
private settingsService: AlfrescoSettingsService,
private translateService: AlfrescoTranslationService,
private storage: StorageService,
private logService: LogService) {
this.setProvider();
if (translateService) {
translateService.addTranslationFolder('app', 'resources');
}
}
isAPageWithHeaderBar(): boolean {
return location.pathname === '/login' || location.pathname === '/settings';
}
onLogout(event) {
event.preventDefault();
this.authService.logout()
.subscribe(
() => {
this.navigateToLogin();
},
(error: any) => {
if (error && error.response && error.response.status === 401) {
this.navigateToLogin();
} else {
this.logService.error('An unknown error occurred while logging out', error);
this.navigateToLogin();
}
}
);
}
navigateToLogin() {
this.router.navigate(['/login']);
this.hideDrawer();
}
onToggleSearch(event) {
let expandedHeaderClass = 'header-search-expanded',
header = document.querySelector('header');
if (event.expanded) {
header.classList.add(expandedHeaderClass);
} else {
header.classList.remove(expandedHeaderClass);
}
}
changeLanguage(lang: string) {
this.translateService.use(lang);
this.hideDrawer();
}
hideDrawer() {
// todo: workaround for drawer closing
document.querySelector('.mdl-layout').MaterialLayout.toggleDrawer();
}
private setProvider() {
if (this.storage.hasItem(`providers`)) {
this.settingsService.setProviders(this.storage.getItem(`providers`));
}
}
onDragOverMainPage(event: any): boolean {
event.preventDefault();
return false;
}
}
+128
View File
@@ -0,0 +1,128 @@
/*!
* @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 { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { CoreModule, AppConfigService } from 'ng2-alfresco-core';
import { SearchModule } from 'ng2-alfresco-search';
import { LoginModule } from 'ng2-alfresco-login';
import { DataTableModule } from 'ng2-alfresco-datatable';
import { DocumentListModule } from 'ng2-alfresco-documentlist';
import { UploadModule } from 'ng2-alfresco-upload';
import { TagModule } from 'ng2-alfresco-tag';
import { SocialModule } from 'ng2-alfresco-social';
import { WebScriptModule } from 'ng2-alfresco-webscript';
import { ViewerModule } from 'ng2-alfresco-viewer';
import { ActivitiFormModule } from 'ng2-activiti-form';
import { ActivitiTaskListModule } from 'ng2-activiti-tasklist';
import { ActivitiProcessListModule } from 'ng2-activiti-processlist';
import { UserInfoComponentModule } from 'ng2-alfresco-userinfo';
import { AnalyticsModule } from 'ng2-activiti-analytics';
import { DiagramsModule } from 'ng2-activiti-diagrams';
import { MaterialModule } from './material.module';
import { AppComponent } from './app.component';
import { routing } from './app.routes';
import { CustomEditorsModule } from './components/activiti/custom-editor/custom-editor.component';
import { Editor3DModule } from 'ng2-3d-editor';
import { ChartsModule } from 'ng2-charts';
import { CreateFolderDialog } from './dialogs/create-folder.dialog';
import { DebugAppConfigService } from './services/debug-app-config.service';
import {
HomeComponent,
DataTableDemoComponent,
SearchComponent,
SearchBarComponent,
LoginDemoComponent,
ActivitiDemoComponent,
ActivitiShowDiagramComponent,
ActivitiAppsView,
FormViewer,
WebscriptComponent,
TagComponent,
SocialComponent,
AboutComponent,
FilesComponent,
FormNodeViewer,
SettingsComponent,
FormDemoComponent
} from './components/index';
let appConfigFile = 'app.config-dev.json';
if (process.env.ENV === 'production') {
appConfigFile = 'app.config-prod.json';
}
@NgModule({
imports: [
BrowserModule,
routing,
CoreModule.forRoot({
appConfigFile: appConfigFile
}),
MaterialModule,
LoginModule.forRoot(),
SearchModule.forRoot(),
DataTableModule.forRoot(),
DocumentListModule.forRoot(),
UploadModule.forRoot(),
TagModule.forRoot(),
SocialModule.forRoot(),
WebScriptModule.forRoot(),
ViewerModule.forRoot(),
ActivitiFormModule.forRoot(),
ActivitiTaskListModule.forRoot(),
ActivitiProcessListModule.forRoot(),
UserInfoComponentModule.forRoot(),
AnalyticsModule.forRoot(),
DiagramsModule.forRoot(),
CustomEditorsModule,
Editor3DModule.forRoot(),
ChartsModule
],
declarations: [
AppComponent,
HomeComponent,
DataTableDemoComponent,
SearchComponent,
SearchBarComponent,
LoginDemoComponent,
ActivitiDemoComponent,
ActivitiShowDiagramComponent,
ActivitiAppsView,
FormViewer,
WebscriptComponent,
TagComponent,
SocialComponent,
AboutComponent,
FilesComponent,
FormNodeViewer,
CreateFolderDialog,
SettingsComponent,
FormDemoComponent
],
providers: [
{ provide: AppConfigService, useClass: DebugAppConfigService }
],
bootstrap: [ AppComponent ],
entryComponents: [
CreateFolderDialog
]
})
export class AppModule { }
+138
View File
@@ -0,0 +1,138 @@
/*!
* @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 { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { AuthGuard, AuthGuardEcm, AuthGuardBpm } from 'ng2-alfresco-core';
import {
HomeComponent,
FilesComponent,
DataTableDemoComponent,
SearchComponent,
LoginDemoComponent,
ActivitiDemoComponent,
ActivitiShowDiagramComponent,
ActivitiAppsView,
WebscriptComponent,
TagComponent,
SocialComponent,
AboutComponent,
FormViewer,
FormNodeViewer,
SettingsComponent,
FormDemoComponent
} from './components/index';
import { UploadButtonComponent } from 'ng2-alfresco-upload';
export const appRoutes: Routes = [
{ path: 'login', component: LoginDemoComponent },
{
path: '',
component: HomeComponent,
canActivate: [AuthGuard]
},
{
path: 'home',
component: HomeComponent,
canActivate: [AuthGuard]
},
{
path: 'files',
component: FilesComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'files/:id',
component: FilesComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'datatable',
component: DataTableDemoComponent,
canActivate: [AuthGuard]
},
{
path: 'uploader',
component: UploadButtonComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'search',
component: SearchComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'activiti',
component: ActivitiAppsView,
canActivate: [AuthGuardBpm]
},
{
path: 'activiti/apps',
component: ActivitiAppsView,
canActivate: [AuthGuardBpm]
},
{
path: 'activiti/apps/:appId/tasks',
component: ActivitiDemoComponent,
canActivate: [AuthGuardBpm]
},
{
path: 'activiti/diagram/:processDefinitionId',
component: ActivitiShowDiagramComponent,
canActivate: [AuthGuardBpm]
},
// TODO: check if neeeded
{
path: 'activiti/appId/:appId',
component: ActivitiDemoComponent,
canActivate: [AuthGuardBpm]
},
// TODO: check if needed
{
path: 'activiti/tasks/:id',
component: FormViewer,
canActivate: [AuthGuardBpm]
},
// TODO: check if needed
{
path: 'activiti/tasksnode/:id',
component: FormNodeViewer,
canActivate: [AuthGuardBpm]
},
{
path: 'webscript',
component: WebscriptComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'tag',
component: TagComponent,
canActivate: [AuthGuardEcm]
},
{
path: 'social',
component: SocialComponent,
canActivate: [AuthGuardEcm]
},
{ path: 'about', component: AboutComponent },
{ path: 'settings', component: SettingsComponent },
{ path: 'form', component: FormDemoComponent }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(appRoutes);
@@ -0,0 +1,3 @@
.about-container {
padding: 10px;
}
@@ -0,0 +1,25 @@
<div class="about-container">
<h3>Server settings</h3>
<small>The values below are taken from the AppConfigService and loaded from the '{{ configFile }}' file.</small>
<div>
Alfresco Process Services URL: <strong>{{ bpmHost }}</strong>
</div>
<div>
Alfresco Content Services URL: <strong>{{ ecmHost }}</strong>
</div>
<div *ngIf="githubUrlCommitAlpha">
<h3>Source code</h3>
<small>You are running the project based on the following commit:</small>
<div>
<a [href]="githubUrlCommitAlpha">{{githubUrlCommitAlpha}}</a>
</div>
</div>
<h3>Packages</h3>
<small>Current project is using the following ADF libraries:</small>
<alfresco-datatable [data]="data"></alfresco-datatable>
</div>
@@ -0,0 +1,89 @@
/*!
* @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 { Component, OnInit } from '@angular/core';
import { Http } from '@angular/http';
import { ObjectDataTableAdapter } from 'ng2-alfresco-datatable';
import { LogService, AppConfigService } from 'ng2-alfresco-core';
@Component({
selector: 'about-page',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
})
export class AboutComponent implements OnInit {
data: ObjectDataTableAdapter;
githubUrlCommitAlpha: string = 'https://github.com/Alfresco/alfresco-ng2-components/commits/';
configFile: string = '';
ecmHost: string = '';
bpmHost: string = '';
constructor(private http: Http,
private appConfig: AppConfigService,
private logService: LogService) {
}
ngOnInit() {
this.http.get('/versions.json').subscribe(response => {
let regexp = new RegExp('^(ng2-activiti|ng2-alfresco|alfresco-)');
let alfrescoPackages = Object.keys(response.json().dependencies).filter((val) => {
this.logService.log(val);
return regexp.test(val);
});
let alfrescoPackagesTableRepresentation = [];
alfrescoPackages.forEach((val) => {
this.logService.log(response.json().dependencies[val]);
alfrescoPackagesTableRepresentation.push({
name: val,
version: response.json().dependencies[val].version
});
});
this.gitHubLinkCreation(alfrescoPackagesTableRepresentation);
this.logService.log(alfrescoPackagesTableRepresentation);
this.data = new ObjectDataTableAdapter(alfrescoPackagesTableRepresentation, [
{type: 'text', key: 'name', title: 'Name', sortable: true},
{type: 'text', key: 'version', title: 'Version', sortable: true}
]);
});
this.configFile = this.appConfig.configFile;
this.ecmHost = this.appConfig.get<string>('ecmHost');
this.bpmHost = this.appConfig.get<string>('bpmHost');
}
private gitHubLinkCreation(alfrescoPackagesTableRepresentation): void {
let corePackage = alfrescoPackagesTableRepresentation.find((packageUp) => {
return packageUp.name === 'ng2-alfresco-core';
});
if (corePackage) {
let commitIsh = corePackage.version.split('-');
if (commitIsh.length > 1) {
this.githubUrlCommitAlpha = this.githubUrlCommitAlpha + commitIsh[1];
} else {
this.githubUrlCommitAlpha = this.githubUrlCommitAlpha + corePackage.version;
}
}
}
}
@@ -0,0 +1,40 @@
.activiti-task-list__item:hover {
cursor: pointer;
font-weight: bold;
}
.activiti {
background-color: #f5f5f5;
}
.task-column {
background-color: #f5f5f5;
padding: 10px 10px 10px 10px;
}
.list-column {
width: 320px;
}
.mdl-layout__header {
z-index: 1;
}
.list-buttons {
text-align: left;
margin-bottom: 5px;
}
.adf-no-form-container {
text-align: center;
font-weight: 600;
font-size: 18px;
font-family: Muli;
padding: 16px;
}
.action-header {
border: 1px solid rgb(224, 224, 224);
background: #fff;
text-align: left;
}
@@ -0,0 +1,231 @@
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<!-- TABS -->
<div class="mdl-layout__tab-bar mdl-js-ripple-effect">
<a id="tasks-header" href="#tasks" class="mdl-layout__tab" [class.is-active]="activeTab === 'tasks'" (click)="activeTab = 'tasks'">TASKS</a>
<a id="processes-header" href="#processes" class="mdl-layout__tab" [class.is-active]="activeTab === 'processes'" (click)="activeTab = 'processes'">PROCESSES</a>
<a id="report-header" href="#report" class="mdl-layout__tab" [class.is-active]="activeTab === 'reports'" (click)="activeTab = 'reports'">REPORTS</a>
</div>
</header>
<main class="mdl-layout__content activiti">
<!-- TASKS COMPONENT -->
<section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'tasks'" id="tasks">
<div class="page-content">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
<div class="list-buttons">
<activiti-start-task
[appId]="appId"
(onSuccess)="onStartTaskSuccess($event)">
</activiti-start-task>
</div>
<adf-accordion>
<adf-accordion-group [heading]="'Tasks'" [isSelected]="true" [isOpen]="true" [headingIcon]="'assignment'">
<activiti-filters
[filterParam]="{name:'MY tasks'}"
[appId]="appId"
[hasIcon]="false"
(filterClick)="onTaskFilterClick($event)"
(onSuccess)="onSuccessTaskFilterList($event)"
#activitifilter>
</activiti-filters>
</adf-accordion-group>
</adf-accordion>
</div>
<div class="mdl-cell mdl-cell--3-col task-column mdl-shadow--2dp list-column">
<activiti-tasklist
[appId]="taskFilter?.appId"
[processDefinitionKey]="taskFilter?.filter?.processDefinitionKey"
[name]="taskFilter?.filter?.name"
[assignment]="taskFilter?.filter?.assignment"
[state]="taskFilter?.filter?.state"
[sort]="taskFilter?.filter?.sort"
[data]="dataTasks"
[landingTaskId]="currentTaskId"
(rowClick)="onTaskRowClick($event)"
(onSuccess)="onSuccessTaskList($event)"
(row-click)="onRowClick($event)"
(row-dblclick)="onRowDblClick($event)"
#activititasklist>
<!-- Custom column definition demo -->
<!--
<data-columns>
<data-column key="name" title="NAME" class="full-width name-column"></data-column>
<data-column key="created" title="Created" class="hidden"></data-column>
</data-columns>
-->
</activiti-tasklist>
</div>
<div class="mdl-cell mdl-cell--7-col task-column mdl-shadow--2dp">
<activiti-task-details #activitidetails
[debugMode]="true"
[taskId]="currentTaskId"
(formCompleted)="onFormCompleted($event)"
(formContentClicked)="onFormContentClick($event)"
(taskCreated)="onTaskCreated($event)"
(taskDeleted)="onTaskDeleted($event)">
</activiti-task-details>
<hr>
<div id="attachment-task-list" *ngIf="currentTaskId">
<h5>Attachments</h5>
<div class="adf-no-form-container">
<div class="action-header">
<button [attr.disabled]="isTaskCompleted()" class="mdl-button mdl-js-button" (click)="toggleCreateTakAttach()">
Attach Document
<i class="material-icons">add</i>
</button>
</div>
<adf-task-attachment-list #taskAttach
*ngIf="currentTaskId"
[taskId]="currentTaskId"
(attachmentClick)="onAttachmentClick($event)">
</adf-task-attachment-list>
<div *ngIf="isCreateTaskAttachVisible()">
<adf-create-task-attachment *ngIf="currentTaskId"
[taskId]="currentTaskId"
(success)="onCreateTaskSuccess()">
</adf-create-task-attachment>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- PROCESS COMPONENT -->
<section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'processes'" id="processes">
<div class="page-content" *ngIf="activeTab === 'processes'">
<div class="page-content">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--2-col task-column mdl-shadow--2dp">
<div class="list-buttons">
<button
md-raised-button
data-automation-id="btn-start-process"
(click)="navigateStartProcess()">
<md-icon>add</md-icon>
<span>START PROCESS</span>
</button>
</div>
<adf-accordion>
<adf-accordion-group [heading]="'Processes'" [isSelected]="true" [isOpen]="true" [headingIcon]="'assessment'">
<activiti-process-instance-filters
[filterParam]="{index: 0}"
[appId]="appId"
(filterClick)="onProcessFilterClick($event)"
(onSuccess)="onSuccessProcessFilterList($event)">
</activiti-process-instance-filters>
</adf-accordion-group>
</adf-accordion>
</div>
<div class="mdl-cell mdl-cell--3-col task-column list-column mdl-shadow--2dp" *ngIf="processFilter && !isStartProcessMode()">
<activiti-process-instance-list
*ngIf="processFilter?.hasFilter()" [appId]="processFilter.appId"
[processDefinitionKey]="processFilter.filter.processDefinitionKey"
[name]="processFilter.filter.name"
[state]="processFilter.filter.state"
[sort]="processFilter.filter.sort"
[data]="dataProcesses"
(rowClick)="onProcessRowClick($event)"
(onSuccess)="onSuccessProcessList($event)">
<!-- Custom column definition demo -->
<!--
<data-columns>
<data-column key="name" title="NAME" class="full-width name-column"></data-column>
<data-column key="created" title="Created" class="hidden"></data-column>
</data-columns>
-->
</activiti-process-instance-list>
</div>
<div class="mdl-cell task-column mdl-shadow--2dp" *ngIf="!isStartProcessMode()"
[class.mdl-cell--7-col]="processFilter && !isStartProcessMode()"
[class.mdl-cell--10-col]="!processFilter || isStartProcessMode()">
<activiti-process-instance-details
[processInstanceId]="currentProcessInstanceId"
(processCancelled)="processCancelled()"
(showProcessDiagram)="onShowProcessDiagram($event)"
(taskClick)="onProcessDetailsTaskClick($event)">
</activiti-process-instance-details>
<hr>
<div id="attachment-process-list" *ngIf="currentProcessInstanceId">
<h5>Attachments</h5>
<div class="action-header">
<button id="show_process_attach" class="mdl-button mdl-js-button" (click)="toggleCreateProcessAttach()">
Attach Document
<i class="material-icons">add</i>
</button>
</div>
<adf-process-attachment-list *ngIf="currentProcessInstanceId"
[processInstanceId]="currentProcessInstanceId"
(attachmentClick)="onAttachmentClick($event)">
</adf-process-attachment-list>
<div *ngIf="isCreateProcessAttachVisible()">
<adf-create-process-attachment *ngIf="currentProcessInstanceId"
[processInstanceId]="currentProcessInstanceId"
(contentCreated)="onContentCreated()">
</adf-create-process-attachment>
</div>
</div>
</div>
<div class="mdl-cell mdl-cell--10-col task-column mdl-shadow--2dp" *ngIf="isStartProcessMode()">
<activiti-start-process [appId]="appId" (start)="onStartProcessInstance($event)"></activiti-start-process>
</div>
</div>
</div>
</div>
</section>
<!-- ANALYTICS COMPONENT -->
<section class="mdl-layout__tab-panel" [class.is-active]="activeTab === 'reports'" id="report">
<div class="page-content" *ngIf="activeTab === 'reports'">
<div class="mdl-grid">
<div class="mdl-cell mdl-cell--4-col task-column mdl-shadow--2dp">
<span><h5>Report List</h5></span>
<hr>
<analytics-report-list
[appId]="appId"
[selectFirst]="selectFirstReport"
(reportClick)="onReportClick($event)"
#analyticsreportlist>
</analytics-report-list>
</div>
<div class="mdl-cell mdl-cell--8-col task-column mdl-shadow--2dp">
<activiti-analytics
*ngIf="report"
[appId]="appId"
[reportId]="report.id"
[hideParameters]="false"
(editReport)="onEditReport($event)"
(reportSaved)="onReportSaved($event)"
(reportDeleted)="onReportDeleted()">
</activiti-analytics>
<div *ngIf="!report">
<span>{{'ANALYTICS_REPORT.NO_REPORT_MESSAGE' | translate}}</span>
</div>
</div>
</div>
</div>
</section>
</main>
</div>
<div *ngIf="fileShowed">
<alfresco-viewer
[(showViewer)]="fileShowed"
[blobFile]="content"
[displayName]="contentName"
[overlayMode]="true">
</alfresco-viewer>
</div>
@@ -0,0 +1,377 @@
/*!
* @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 { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core';
import {
ActivitiApps,
ActivitiFilters,
ActivitiTaskList,
ActivitiTaskDetails,
FilterRepresentationModel,
TaskDetailsEvent,
TaskAttachmentListComponent
} from 'ng2-activiti-tasklist';
import {
ActivitiProcessFilters,
ActivitiProcessInstanceDetails,
ActivitiProcessInstanceListComponent,
ActivitiStartProcessInstance,
FilterProcessRepresentationModel,
ProcessInstance,
ActivitiProcessAttachmentListComponent
} from 'ng2-activiti-processlist';
import { AnalyticsReportListComponent } from 'ng2-activiti-analytics';
import { ActivatedRoute, Router } from '@angular/router';
import { Subscription } from 'rxjs/Rx';
import {
ObjectDataTableAdapter,
ObjectDataRow,
DataSorting
} from 'ng2-alfresco-datatable';
import { AlfrescoApiService } from 'ng2-alfresco-core';
import { FormService, FormRenderingService, FormEvent, FormFieldEvent } from 'ng2-activiti-form';
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
declare var componentHandler;
const currentProcessIdNew = '__NEW__';
@Component({
selector: 'activiti-demo',
templateUrl: './activiti-demo.component.html',
styleUrls: ['./activiti-demo.component.css']
})
export class ActivitiDemoComponent implements AfterViewInit {
@ViewChild(ActivitiFilters)
activitifilter: ActivitiFilters;
@ViewChild(ActivitiTaskList)
taskList: ActivitiTaskList;
@ViewChild(TaskAttachmentListComponent)
taskAttachList: TaskAttachmentListComponent;
@ViewChild(ActivitiProcessFilters)
activitiprocessfilter: ActivitiProcessFilters;
@ViewChild(ActivitiProcessInstanceListComponent)
processList: ActivitiProcessInstanceListComponent;
@ViewChild(ActivitiProcessInstanceDetails)
activitiprocessdetails: ActivitiProcessInstanceDetails;
@ViewChild(ActivitiTaskDetails)
activitidetails: ActivitiTaskDetails;
@ViewChild(ActivitiProcessAttachmentListComponent)
processAttachList: ActivitiProcessAttachmentListComponent;
@ViewChild(ActivitiStartProcessInstance)
activitiStartProcess: ActivitiStartProcessInstance;
@ViewChild(AnalyticsReportListComponent)
analyticsreportlist: AnalyticsReportListComponent;
@Input()
appId: number = null;
fileShowed: boolean = false;
selectFirstReport: boolean = false;
content: Blob;
contentName: string;
layoutType: string;
currentTaskId: string;
currentProcessInstanceId: string;
taskSchemaColumns: any [] = [];
processSchemaColumns: any [] = [];
activeTab: string = 'tasks'; // tasks|processes|reports
taskFilter: FilterRepresentationModel;
report: any;
processFilter: FilterProcessRepresentationModel;
sub: Subscription;
blobFile: any;
flag: boolean = true;
createTaskAttach: boolean = false;
createProcessAttach: boolean = false;
dataTasks: ObjectDataTableAdapter;
dataProcesses: ObjectDataTableAdapter;
constructor(private elementRef: ElementRef,
private route: ActivatedRoute,
private router: Router,
private apiService: AlfrescoApiService,
private formRenderingService: FormRenderingService,
private formService: FormService) {
this.dataTasks = new ObjectDataTableAdapter();
this.dataTasks.setSorting(new DataSorting('created', 'desc'));
this.dataProcesses = new ObjectDataTableAdapter(
[],
[
{ type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true },
{ type: 'text', key: 'started', title: 'Started', cssClass: 'hidden', sortable: true }
]
);
this.dataProcesses.setSorting(new DataSorting('started', 'desc'));
// Uncomment this line to replace all 'text' field editors with custom component
// formRenderingService.setComponentTypeResolver('text', () => CustomEditorComponent, true);
// Uncomment this line to map 'custom_stencil_01' to local editor component
formRenderingService.setComponentTypeResolver('custom_stencil_01', () => CustomStencil01, true);
formService.formLoaded.subscribe((e: FormEvent) => {
console.log(`Form loaded: ${e.form.id}`);
});
formService.formFieldValueChanged.subscribe((e: FormFieldEvent) => {
console.log(`Field value changed. Form: ${e.form.id}, Field: ${e.field.id}, Value: ${e.field.value}`);
});
formService.formEvents.subscribe((event: Event) => {
console.log('Event fired:' + event.type);
console.log('Event Target:' + event.target);
});
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
let applicationId = params['appId'];
if (applicationId && applicationId !== '0') {
this.appId = params['appId'];
}
this.taskFilter = null;
this.currentTaskId = null;
this.processFilter = null;
this.currentProcessInstanceId = null;
});
this.layoutType = ActivitiApps.LAYOUT_GRID;
}
ngOnDestroy() {
this.sub.unsubscribe();
}
onTaskFilterClick(filter: FilterRepresentationModel): void {
this.applyTaskFilter(filter);
}
onReportClick(event: any): void {
this.report = event;
}
onSuccessTaskFilterList(event: any): void {
this.applyTaskFilter(this.activitifilter.getCurrentFilter());
}
applyTaskFilter(filter: FilterRepresentationModel) {
this.taskFilter = filter;
if (filter && this.taskList) {
this.taskList.hasCustomDataSource = false;
}
}
onStartTaskSuccess(event: any): void {
this.activitifilter.selectFilterWithTask(event.id);
this.currentTaskId = event.id;
}
onSuccessTaskList(event: FilterRepresentationModel) {
this.currentTaskId = this.taskList.getCurrentId();
}
onProcessFilterClick(event: FilterProcessRepresentationModel): void {
this.currentProcessInstanceId = null;
this.processFilter = event;
}
onSuccessProcessFilterList(): void {
this.processFilter = this.activitiprocessfilter.getCurrentFilter();
}
onSuccessProcessList(event: any): void {
this.currentProcessInstanceId = this.processList.getCurrentId();
}
onTaskRowClick(taskId): void {
this.currentTaskId = taskId;
}
onProcessRowClick(processInstanceId): void {
this.currentProcessInstanceId = processInstanceId;
}
onEditReport(name: string): void {
this.analyticsreportlist.reload();
}
onReportSaved(reportId): void {
this.analyticsreportlist.reload(reportId);
}
onReportDeleted(): void {
this.analyticsreportlist.reload();
this.analyticsreportlist.selectReport(null);
}
navigateStartProcess(): void {
this.resetProcessFilters();
this.reloadProcessFilters();
this.currentProcessInstanceId = currentProcessIdNew;
}
onStartProcessInstance(instance: ProcessInstance): void {
this.currentProcessInstanceId = instance.id;
this.activitiStartProcess.reset();
this.resetProcessFilters();
}
isStartProcessMode(): boolean {
return this.currentProcessInstanceId === currentProcessIdNew;
}
processCancelled(data: any): void {
this.currentProcessInstanceId = null;
this.processList.reload();
}
onSuccessNewProcess(data: any): void {
this.processList.reload();
}
onFormCompleted(form): void {
this.taskList.reload();
this.currentTaskId = null;
}
onFormContentClick(content: any): void {
this.fileShowed = true;
this.content = content.contentBlob;
this.contentName = content.name;
}
onAttachmentClick(content: any): void {
this.fileShowed = true;
this.content = content.contentBlob;
this.contentName = content.name;
}
onTaskCreated(data: any): void {
this.currentTaskId = data.parentTaskId;
this.taskList.reload();
}
onTaskDeleted(data: any): void {
this.taskList.reload();
}
ngAfterViewInit() {
// workaround for MDL issues with dynamic components
if (componentHandler) {
componentHandler.upgradeAllRegistered();
}
this.loadStencilScriptsInPageFromActiviti();
}
loadStencilScriptsInPageFromActiviti() {
this.apiService.getInstance().activiti.scriptFileApi.getControllers().then(response => {
if (response) {
let s = document.createElement('script');
s.type = 'text/javascript';
s.text = response;
this.elementRef.nativeElement.appendChild(s);
}
});
}
onShowProcessDiagram(event: any): void {
this.router.navigate(['/activiti/diagram/' + event.value]);
}
onProcessDetailsTaskClick(event: TaskDetailsEvent): void {
event.preventDefault();
this.activeTab = 'tasks';
const taskId = event.value.id;
const processTaskDataRow = new ObjectDataRow({
id: taskId,
name: event.value.name || 'No name',
created: event.value.created
});
this.activitifilter.selectFilter(null);
this.taskList.setCustomDataSource([processTaskDataRow]);
this.taskList.selectTask(taskId);
this.currentTaskId = taskId;
}
private resetProcessFilters(): void {
this.processFilter = null;
}
private reloadProcessFilters(): void {
this.activitiprocessfilter.selectFilter(null);
}
onRowClick(event): void {
console.log(event);
}
onRowDblClick(event): void {
console.log(event);
}
onCreateTaskSuccess(): void {
this.taskAttachList.reload();
this.toggleCreateTakAttach();
}
onContentCreated() {
this.processAttachList.reload();
this.toggleCreateProcessAttach();
}
toggleCreateTakAttach(): void {
this.createTaskAttach = !this.createTaskAttach;
}
isCreateTaskAttachVisible(): boolean {
return this.createTaskAttach;
}
toggleCreateProcessAttach(): void {
this.createProcessAttach = !this.createProcessAttach;
}
isCreateProcessAttachVisible(): boolean {
return this.createProcessAttach;
}
isTaskCompleted(): boolean {
return this.activitidetails.isCompletedTask();
}
}
@@ -0,0 +1,6 @@
<div>
<button (click)="onClickBack()" class="mdl-button mdl-button--icon">
<i class="material-icons">keyboard_backspace</i>
</button>
<activiti-diagram [processInstanceId]="processDefinitionId"></activiti-diagram>
</div>
@@ -0,0 +1,49 @@
/*!
* @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 { Component } from '@angular/core';
import { Subscription } from 'rxjs/Rx';
import { ActivatedRoute } from '@angular/router';
import {Location} from '@angular/common';
@Component({
selector: 'activiti-show-diagram',
templateUrl: './activiti-show-diagram.component.html',
styleUrls: ['./activiti-show-diagram.component.css']
})
export class ActivitiShowDiagramComponent {
sub: Subscription;
processDefinitionId: string;
constructor(private route: ActivatedRoute,
private location: Location) {
this.sub = this.route.params.subscribe(params => {
this.processDefinitionId = params['processDefinitionId'];
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
onClickBack() {
this.location.back();
}
}
@@ -0,0 +1,37 @@
/*!
* @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 { Component } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { AppDefinitionRepresentationModel } from 'ng2-activiti-tasklist';
@Component({
selector: 'activiti-apps-view',
template: `
<activiti-apps (appClick)="onAppClicked($event)"></activiti-apps>
`
})
export class ActivitiAppsView {
constructor(private router: Router, private route: ActivatedRoute) {
}
onAppClicked(app: AppDefinitionRepresentationModel) {
this.router.navigate(['/activiti/apps', app.id || 0, 'tasks']);
}
}
@@ -0,0 +1,52 @@
/*!
* @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 { NgModule, Component } from '@angular/core';
import { WidgetComponent } from 'ng2-activiti-form';
@Component({
selector: 'custom-editor',
template: `
<div style="color: red">Look, I'm a custom editor!</div>
`
})
export class CustomEditorComponent extends WidgetComponent {
constructor() {
super();
}
}
@Component({
selector: 'custom-stencil-01',
template: `<div style="color: green">ADF version of custom Activiti stencil</div>`
})
export class CustomStencil01 extends WidgetComponent {
constructor() {
super();
}
}
@NgModule({
declarations: [ CustomEditorComponent, CustomStencil01 ],
exports: [ CustomEditorComponent, CustomStencil01 ],
entryComponents: [ CustomEditorComponent, CustomStencil01 ]
})
export class CustomEditorsModule {
}
@@ -0,0 +1,3 @@
.activiti-form-viewer {
margin: 10px;
}
@@ -0,0 +1,6 @@
<div class="activiti-form-viewer" *ngIf="nodeId">
<activiti-form [nodeId]="nodeId"
[saveMetadata]="true"
[path]="'/Sites/swsdp/documentLibrary'">
</activiti-form>
</div>
@@ -0,0 +1,55 @@
/*!
* @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 { Component, OnInit, OnDestroy, AfterViewChecked } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Rx';
declare var componentHandler;
@Component({
selector: 'form-node-viewer',
templateUrl: './form-node-viewer.component.html',
styleUrls: ['./form-node-viewer.component.css']
})
export class FormNodeViewer implements OnInit, OnDestroy, AfterViewChecked {
nodeId: string;
private sub: Subscription;
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.nodeId = params['id'];
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
ngAfterViewChecked() {
// workaround for MDL issues with dynamic components
if (componentHandler) {
componentHandler.upgradeAllRegistered();
}
}
}
@@ -0,0 +1,3 @@
.activiti-form-viewer {
margin: 10px;
}
@@ -0,0 +1,11 @@
<div class="activiti-form-viewer" *ngIf="taskId">
<activiti-form [taskId]="taskId"></activiti-form>
<!--<activiti-form [formName]="'activitiForms:patientFolder'"-->
<!--[saveMetadata]="true"-->
<!--[path]="'/Sites/swsdp/documentLibrary'"-->
<!--[nameNode]="'test'"></activiti-form>-->
<!--<activiti-form [nodeId]="'e280be3a-6584-45a1-8bb5-89bfe070262e'"-->
<!--[saveMetadata]="true"-->
<!--[path]="'/Sites/swsdp/documentLibrary'">-->
<!--</activiti-form>-->
</div>
@@ -0,0 +1,55 @@
/*!
* @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 { Component, OnInit, OnDestroy, AfterViewChecked } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Rx';
declare var componentHandler;
@Component({
selector: 'form-viewer',
templateUrl: './form-viewer.component.html',
styleUrls: ['./form-viewer.component.css']
})
export class FormViewer implements OnInit, OnDestroy, AfterViewChecked {
taskId: string;
private sub: Subscription;
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
this.taskId = params['id'];
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
ngAfterViewChecked() {
// workaround for MDL issues with dynamic components
if (componentHandler) {
componentHandler.upgradeAllRegistered();
}
}
}
@@ -0,0 +1,10 @@
alfresco-datatable >>> .custom-row-style.alfresco-datatable__row:focus {
outline-offset: -1px;
outline-width: 1px;
outline-color: green;
outline-style: solid;
}
alfresco-datatable >>> .custom-row-style.alfresco-datatable__row--selected {
color: green;
}
@@ -0,0 +1,40 @@
<div class="p-10">
<alfresco-datatable
[data]="data"
[selectionMode]="selectionMode"
[multiselect]="multiselect"
[actions]="true"
rowStyleClass="custom-row-style"
(showRowActionsMenu)="onShowRowActionsMenu($event)"
(executeRowAction)="onExecuteRowAction($event)"
(row-click)="onRowClick($event)"
(row-dblclick)="onRowDblClick($event)">
<!-- HTML column definition demo -->
<!--
<data-columns>
<data-column type="image" key="icon" [sortable]="false"></data-column>
<data-column key="id" title="Id"></data-column>
<data-column key="createdOn" title="Created"></data-column>
<data-column key="name" title="Name" class="full-width name-column"></data-column>
<data-column key="createdBy.name" title="Created By"></data-column>
</data-columns>
-->
</alfresco-datatable>
</div>
<div class="p-10" data-automation-id="multiselect">
<md-checkbox [(ngModel)]="multiselect">Multiselect</md-checkbox>
</div>
<div class="p-10">
<p>For 'Multiple' selection mode use Cmd (macOS) or Ctrl (Win) to toggle selection of multiple items.</p>
<md-select placeholder="Selection Mode" [(ngModel)]="selectionMode" name="food">
<md-option *ngFor="let mode of selectionModes" [value]="mode.value">
{{mode.viewValue}}
</md-option>
</md-select>
</div>
<div class="p-10">
<button md-raised-button (click)="reset()">Reset to default</button>
<button md-raised-button (click)="addRow()">Add row</button>
<button md-raised-button (click)="replaceRows()">Replace rows</button>
<button md-raised-button (click)="replaceColumns()">Replace columns</button>
</div>
@@ -0,0 +1,175 @@
/*!
* @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 { Component, Input } from '@angular/core';
import { ObjectDataTableAdapter, DataSorting, ObjectDataRow, ObjectDataColumn, DataCellEvent, DataRowActionEvent } from 'ng2-alfresco-datatable';
@Component({
selector: 'datatable-demo',
templateUrl: './datatable-demo.component.html',
styleUrls: ['./datatable-demo.component.css']
})
export class DataTableDemoComponent {
multiselect: boolean = false;
data: ObjectDataTableAdapter;
@Input()
selectionMode = 'single';
selectionModes = [
{ value: 'none', viewValue: 'None' },
{ value: 'single', viewValue: 'Single' },
{ value: 'multiple', viewValue: 'Multiple' }
];
private _imageUrl: string = 'http://placehold.it/140x100';
private _createdBy: any = {
name: 'Denys Vuika',
email: 'denys.vuika@alfresco.com'
};
constructor() {
this.reset();
}
reset() {
this.data = new ObjectDataTableAdapter(
[
{
id: 1,
name: 'Name 1',
createdOn: new Date(2016, 6, 2, 15, 8, 1),
createdBy: this._createdBy,
icon: 'material-icons://folder_open'
},
{
id: 2,
name: 'Name 2',
createdOn: new Date(2016, 6, 2, 15, 8, 2),
createdBy: this._createdBy,
icon: 'material-icons://accessibility'
},
{
id: 3,
name: 'Name 3',
createdOn: new Date(2016, 6, 2, 15, 8, 3),
createdBy: this._createdBy,
icon: 'material-icons://alarm'
},
{
id: 4,
name: 'Image 1',
createdOn: new Date(2016, 6, 2, 15, 8, 4),
createdBy: this._createdBy,
icon: this._imageUrl
}
],
[
{type: 'image', key: 'icon', title: '', srTitle: 'Thumbnail'},
{type: 'text', key: 'id', title: 'Id', sortable: true},
{type: 'text', key: 'createdOn', title: 'Created On', sortable: true},
{type: 'text', key: 'name', title: 'Name', cssClass: 'full-width name-column', sortable: true},
{type: 'text', key: 'createdBy.name', title: 'Created By', sortable: true}
]
);
this.data.setSorting(new DataSorting('id', 'asc'));
}
addRow() {
let id = this.data.getRows().length + 1;
let row = new ObjectDataRow({
id: id,
name: 'Name ' + id,
createdOn: new Date(),
icon: 'material-icons://extension',
createdBy: this._createdBy
});
this.data.getRows().push(row);
this.data.sort();
}
replaceRows() {
let objects = [
{
id: 10,
name: 'Name 10',
createdBy: this._createdBy,
createdOn: new Date(2016, 6, 2, 15, 8, 5),
icon: 'material-icons://face'
},
{
id: 11,
name: 'Name 11',
createdBy: this._createdBy,
createdOn: new Date(2016, 6, 2, 15, 8, 6),
icon: 'material-icons://language'
},
{
id: 12,
name: 'Name 12',
createdBy: this._createdBy,
createdOn: new Date(2016, 6, 2, 15, 8, 7),
icon: 'material-icons://pets'
},
{
id: 13,
name: 'Image 13',
createdBy: this._createdBy,
createdOn: new Date(2016, 6, 2, 15, 8, 8),
icon: this._imageUrl
}
];
let rows = objects.map(obj => new ObjectDataRow(obj));
this.data.setRows(rows);
}
replaceColumns() {
let schema = [
{ type: 'text', key: 'id', title: 'Id', sortable: true },
{ type: 'text', key: 'name', title: 'Name', sortable: true, cssClass: 'full-width name-column' }
];
let columns = schema.map(col => new ObjectDataColumn(col));
this.data.setColumns(columns);
}
onShowRowActionsMenu(event: DataCellEvent) {
let myAction = {
title: 'Hello'
// you custom metadata needed for onExecuteRowAction
};
event.value.actions = [
myAction
];
}
onExecuteRowAction(event: DataRowActionEvent) {
let args = event.value;
console.log(args.row);
console.log(args.action);
window.alert(`My custom action: ${args.action.title}`);
}
onRowClick(event) {
console.log(event);
}
onRowDblClick(event) {
console.log(event);
}
}
@@ -0,0 +1,21 @@
.container {
margin: 10px;
}
@media only screen and (max-width: 640px) {
.container {
margin: 0;
}
}
.error-message {
text-align: left;
}
.error-message--text {
color: #d50000;
}
.adf-not-overlay-viewer {
height:900px;
}
@@ -0,0 +1,220 @@
<div class="container">
<alfresco-upload-drag-area
[rootFolderId]="documentList.currentFolderId"
[versioning]="versioning"
[enabled]="documentList.hasCreatePermission()">
<adf-breadcrumb
[target]="documentList"
[folderNode]="documentList.folderNode">
</adf-breadcrumb>
<div *ngIf="errorMessage" class="error-message">
<button (click)="resetError()" class="mdl-button mdl-js-button mdl-button--icon">
<i class="material-icons">highlight_off</i>
</button>
<span class="error-message--text">{{errorMessage}}</span>
</div>
<ng-container *ngIf="useCustomToolbar">
<adf-toolbar title="Toolbar">
<button md-icon-button (click)="onCreateFolderClicked($event)">
<md-icon>create_new_folder</md-icon>
</button>
<button md-icon-button>
<md-icon>delete</md-icon>
</button>
<button md-icon-button [mdMenuTriggerFor]="menu">
<md-icon>more_vert</md-icon>
</button>
<md-menu #menu="mdMenu">
<button md-menu-item>
<md-icon>dialpad</md-icon>
<span>Redial</span>
</button>
<button md-menu-item disabled>
<md-icon>voicemail</md-icon>
<span>Check voicemail</span>
</button>
<button md-menu-item>
<md-icon>notifications_off</md-icon>
<span>Disable alerts</span>
</button>
</md-menu>
</adf-toolbar>
</ng-container>
<alfresco-document-list
#documentList
[creationMenuActions]="!useCustomToolbar"
[currentFolderId]="currentFolderId"
[contextMenuActions]="true"
[contentActions]="true"
[allowDropFiles]="true"
(error)="onNavigationError($event)"
(success)="resetError()"
(preview)="showFile($event)"
(permissionError)="handlePermissionError($event)">
<data-columns>
<data-column key="$thumbnail" type="image" [sortable]="false"></data-column>
<data-column
title="{{'DOCUMENT_LIST.COLUMNS.DISPLAY_NAME' | translate}}"
key="name"
class="full-width ellipsis-cell">
<!-- Example #1: using custom template with implicit access to data context -->
<!--
<ng-template let-entry="$implicit">
<span>Hi! {{entry.data.getValue(entry.row, entry.col)}}</span>
</ng-template>
-->
<!-- Example #2: using custom template with value access -->
<!--
<ng-template let-value="value">
<span>Hi! {{value}}</span>
</ng-template>
-->
</data-column>
<!-- Notes: has performance overhead due to multiple files/folders causing separate HTTP calls to get tags -->
<!--
<data-column
title="{{'DOCUMENT_LIST.COLUMNS.TAG' | translate}}"
key="id"
class="full-width ellipsis-cell">
<template let-entry="$implicit">
<alfresco-tag-node-list [nodeId]="entry.data.getValue(entry.row, entry.col)"></alfresco-tag-node-list>
</template>
</data-column>
-->
<data-column
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_BY' | translate}}"
key="createdByUser.displayName"
class="desktop-only">
</data-column>
<data-column
title="{{'DOCUMENT_LIST.COLUMNS.CREATED_ON' | translate}}"
key="createdAt"
type="date"
format="medium"
class="desktop-only">
</data-column>
</data-columns>
<content-actions>
<!-- folder actions -->
<content-action
target="folder"
permission="delete"
[disableWithNoPermission]="true"
title="{{'DOCUMENT_LIST.ACTIONS.FOLDER.DELETE' | translate}}"
(permissionEvent)="handlePermissionError($event)"
handler="delete">
</content-action>
<!-- document actions -->
<content-action
target="document"
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DOWNLOAD' | translate}}"
handler="download">
</content-action>
<content-action
target="document"
permission="delete"
[disableWithNoPermission]="true"
(permissionEvent)="handlePermissionError($event)"
title="{{'DOCUMENT_LIST.ACTIONS.DOCUMENT.DELETE' | translate}}"
handler="delete">
</content-action>
</content-actions>
</alfresco-document-list>
</alfresco-upload-drag-area>
</div>
<context-menu-holder></context-menu-holder>
<div class="container">
<section>
<md-slide-toggle [(ngModel)]="useCustomToolbar">Use custom toolbar</md-slide-toggle>
</section>
<section>
<md-slide-toggle [(ngModel)]="multipleFileUpload">Multiple File Upload</md-slide-toggle>
</section>
<section>
<md-slide-toggle [(ngModel)]="folderUpload">Folder upload</md-slide-toggle>
</section>
<section>
<md-slide-toggle [(ngModel)]="acceptedFilesTypeShow">Custom extensions filter</md-slide-toggle>
</section>
<section>
<md-slide-toggle [(ngModel)]="versioning">Enable versioning</md-slide-toggle>
</section>
<section>
<md-slide-toggle [(ngModel)]="disableWithNoPermission">Disable upload button when user has no permissions</md-slide-toggle>
</section>
<h5>Upload</h5>
<section *ngIf="acceptedFilesTypeShow">
<md-input-container>
<input mdInput placeholder="Extension accepted" [(ngModel)]="acceptedFilesType" data-automation-id="accepted-files-type">
</md-input-container>
</section>
<div *ngIf="!acceptedFilesTypeShow">
<alfresco-upload-button
#uploadButton
[disabled]="!enableUpload"
data-automation-id="multiple-file-upload"
[rootFolderId]="documentList.currentFolderId"
[multipleFiles]="multipleFileUpload"
[uploadFolders]="folderUpload"
[versioning]="versioning"
[disableWithNoPermission]="disableWithNoPermission"
(permissionEvent)="handlePermissionError($event)">
</alfresco-upload-button>
</div>
<div *ngIf="acceptedFilesTypeShow">
<alfresco-upload-button
#uploadButton
[disabled]="!enableUpload"
data-automation-id="multiple-file-upload"
[rootFolderId]="documentList.currentFolderId"
[acceptedFilesType]="acceptedFilesType"
[multipleFiles]="multipleFileUpload"
[uploadFolders]="folderUpload"
[versioning]="versioning"
[disableWithNoPermission]="disableWithNoPermission"
(permissionEvent)="handlePermissionError($event)">
</alfresco-upload-button>
</div>
<section>
<md-checkbox [(ngModel)]="enableUpload">Enable upload (demoing enabled/disabled state)</md-checkbox>
</section>
</div>
<file-uploading-dialog #fileDialog></file-uploading-dialog>
<div *ngIf="fileShowed">
<alfresco-viewer [(showViewer)]="fileShowed"
[fileNodeId]="fileNodeId"
[overlayMode]="true">
<extension-viewer [supportedExtensions]="['obj','3DS']" #extension>
<ng-template let-urlFileContent="urlFileContent" let-extension="extension" >
<threed-viewer [urlFile]="urlFileContent" [extension]="extension" ></threed-viewer>
</ng-template>
</extension-viewer>
</alfresco-viewer>
<!-- Comment the viewer above and uncomment that one below if you want test the overlay false viewer-->
<!--<div *ngIf="fileShowed" class="adf-not-overlay-viewer">-->
<!--<alfresco-viewer [(showViewer)]="fileShowed"-->
<!--[fileNodeId]="fileNodeId"-->
<!--[overlayMode]="false">-->
<!--</alfresco-viewer>-->
<!--</div>-->
</div>
@@ -0,0 +1,145 @@
/*!
* @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 { Component, Input, OnInit, Optional, ViewChild, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/router';
import { MdDialog } from '@angular/material';
import { AlfrescoContentService, FolderCreatedEvent, NotificationService } from 'ng2-alfresco-core';
import { DocumentListComponent } from 'ng2-alfresco-documentlist';
import { UploadService, FileUploadCompleteEvent } from 'ng2-alfresco-upload';
import { CreateFolderDialog } from '../../dialogs/create-folder.dialog';
@Component({
selector: 'files-component',
templateUrl: './files.component.html',
styleUrls: ['./files.component.css']
})
export class FilesComponent implements OnInit {
// The identifier of a node. You can also use one of these well-known aliases: -my- | -shared- | -root-
currentFolderId: string = '-my-';
errorMessage: string = null;
fileNodeId: any;
fileShowed: boolean = false;
useCustomToolbar = true;
@Input()
multipleFileUpload: boolean = false;
@Input()
disableWithNoPermission: boolean = false;
@Input()
folderUpload: boolean = false;
@Input()
acceptedFilesTypeShow: boolean = false;
@Input()
versioning: boolean = false;
@Input()
acceptedFilesType: string = '.jpg,.pdf,.js';
@Input()
enableUpload: boolean = true;
@ViewChild(DocumentListComponent)
documentList: DocumentListComponent;
constructor(private changeDetector: ChangeDetectorRef,
private notificationService: NotificationService,
private uploadService: UploadService,
private contentService: AlfrescoContentService,
private dialog: MdDialog,
@Optional() private route: ActivatedRoute) {
}
showFile(event) {
if (event.value.entry.isFile) {
this.fileNodeId = event.value.entry.id;
this.fileShowed = true;
} else {
this.fileShowed = false;
}
}
toggleFolder() {
this.multipleFileUpload = false;
this.folderUpload = !this.folderUpload;
return this.folderUpload;
}
ngOnInit() {
if (this.route) {
this.route.params.forEach((params: Params) => {
if (params['id']) {
this.currentFolderId = params['id'];
this.changeDetector.detectChanges();
}
});
}
this.uploadService.fileUploadComplete.debounceTime(300).subscribe(value => this.onFileUploadComplete(value));
this.contentService.folderCreated.subscribe(value => this.onFolderCreated(value));
}
onNavigationError(err: any) {
if (err) {
this.errorMessage = err.message || 'Navigation error';
}
}
resetError() {
this.errorMessage = null;
}
onFileUploadComplete(event: FileUploadCompleteEvent) {
if (event && event.file.options.parentId === this.documentList.currentFolderId) {
this.documentList.reload();
}
}
onFolderCreated(event: FolderCreatedEvent) {
console.log('FOLDER CREATED');
console.log(event);
if (event && event.parentId === this.documentList.currentFolderId) {
this.documentList.reload();
}
}
handlePermissionError(event: any) {
this.notificationService.openSnackMessage(
`You don't have the ${event.permission} permission to ${event.action} the ${event.type} `,
4000
);
}
onCreateFolderClicked(event: Event) {
let dialogRef = this.dialog.open(CreateFolderDialog);
dialogRef.afterClosed().subscribe(folderName => {
if (folderName) {
this.contentService.createFolder('', folderName, this.documentList.currentFolderId).subscribe(
node => console.log(node),
err => console.log(err)
);
}
});
}
}

Some files were not shown because too many files have changed in this diff Show More