Skip to content

Commit

Permalink
Merge pull request #147 from netgrif/NAE-1759
Browse files Browse the repository at this point in the history
[NAE-1759] Update documentation of public views, PDF generator and user list
  • Loading branch information
machacjozef committed Feb 1, 2023
2 parents 9b8e6de + d482f5d commit a9e4841
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 124 deletions.
44 changes: 37 additions & 7 deletions docs/roles/userlist.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

## UserList

UserList is a type of data field. Values of this field represent ID of users in the system. Some basic information about
UserList is a type of data field. Values of this field represent users in system. Some basic information about
this field:

- this field currently does not have frontend representation
- this field does not have any init value, because when the process is created or imported, the given user may not exist
- we can add values to this field via actions
- we can add values to this field via actions and using frontend component
- it can serve as definition of permissions for volume of users
- value type of this field is ``UserListFieldValue``

```xml
<data type="userList">
Expand All @@ -17,12 +17,42 @@ this field:
</data>
```

## UsersRef
Example action to change value of this field:
```xml
<action trigger="set">
userList: f.userList1;

<!-- Setting with list of user IDs -->
change userList value { ["userId1", "userId2"] }

<!-- Setting with UserListFieldValue -->
change userList value {
new com.netgrif.application.engine.petrinet.domain.dataset.UserListFieldValue(
[
new com.netgrif.application.engine.petrinet.domain.dataset.UserFieldValue(
"userId1",
"John",
"Doe",
"john@doe.com"
),
new com.netgrif.application.engine.petrinet.domain.dataset.UserFieldValue(
"userId2",
"Alice",
"Doe",
"alice@doe.com"
)
]
)
}
</action>
```

## UserRef

It is a new property of process and transition in PetriNet. It serves as a roleRef with a difference from it: the
content of the userList can be changed at runtime.

- usersRef references userList defined with its ID
- userRef references userList defined with its ID
- we define permissions for usersRef in a same way as for roleRef

```xml
Expand All @@ -33,13 +63,13 @@ content of the userList can be changed at runtime.
<title/>
</data>
...
<usersRef>
<userRef>
<id>userList1</id>
<caseLogic>
<view>true</view>
<delete>true</delete>
</caseLogic>
</usersRef>
</userRef>
...
<transition>
<id>1</id>
Expand Down
45 changes: 45 additions & 0 deletions docs/services/pdf_generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,51 @@ PdfGenerator.generatePdf(Case, String, PdfResource) function takes three argumen
Finally, based on the path or FileFieldValue in the first part of function, you can change a file fields value to the
final PDF file.

If you do not want to define your own implementation of PDF generation action, you still can use the default actions for
generating PDF, which are the followings:

```groovy
@NamedVariant
void generatePDF(String sourceTransitionId, String targetFileFieldId,
Case sourceCase = useCase, Case targetCase = useCase, String targetTransitionId = null,
String template = null, List<String> excludedFields = [], Locale locale = null,
ZoneId dateZoneId = ZoneId.systemDefault(), Integer sideMargin = 75, Integer titleMargin = 20) {
if (!sourceTransitionId || !targetFileFieldId)
throw new IllegalArgumentException("Source transition or target file field is null")
targetTransitionId = targetTransitionId ?: sourceTransitionId
generatePdf(sourceTransitionId, targetFileFieldId, sourceCase, targetCase, targetTransitionId,
template, excludedFields, locale, dateZoneId, sideMargin, titleMargin)
}
void generatePDF(Transition sourceTransition, FileField targetFileField, Case sourceCase = useCase, Case targetCase = useCase,
Transition targetTransition = null, String template = null, List<String> excludedFields = [], Locale locale = null,
ZoneId dateZoneId = ZoneId.systemDefault(), Integer sideMargin = 75, Integer titleMargin = 0) {
if (!sourceTransition || !targetFileField)
throw new IllegalArgumentException("Source transition or target file field is null")
targetTransition = targetTransition ?: sourceTransition
generatePdf(sourceTransition.stringId, targetFileField.importId, sourceCase, targetCase, targetTransition.stringId,
template, excludedFields, locale, dateZoneId, sideMargin, titleMargin)
}
void generatePdf(String transitionId, FileField fileField, List<String> excludedFields = []) {
generatePdf(sourceTransitionId: transitionId, targetFileFieldId: fileField, excludedFields: excludedFields)
}
void generatePdf(String transitionId, String fileFieldId, List<String> excludedFields, Case fromCase = useCase, Case saveToCase = useCase) {
generatePdf(sourceTransitionId: transitionId, targetFileFieldId: fileFieldId, excludedFields: excludedFields, sourceCase: fromCase, targetCase: useCase)
}
void generatePdfWithTemplate(String transitionId, String fileFieldId, String template, Case fromCase = useCase, Case saveToCase = useCase) {
generatePdf(sourceTransitionId: transitionId, targetFileFieldId: fileFieldId, template: template, sourceCase: fromCase, targetCase: saveToCase)
}
void generatePdfWithLocale(String transitionId, String fileFieldId, Locale locale, Case fromCase = useCase, Case saveToCase = useCase) {
generatePdf(sourceTransitionId: transitionId, targetFileFieldId: fileFieldId, locale: locale, sourceCase: fromCase, targetCase: saveToCase)
}
```

These actions can be simply called in your PetriNet action definitions.

## Supported layouts

PDF generator supports standard legacy layout, grid layout and flow layout. You have nothing to do with layout
Expand Down
186 changes: 69 additions & 117 deletions docs/views/public_view.md
Original file line number Diff line number Diff line change
@@ -1,134 +1,86 @@
# Public view

Public view is breaking change in NAE v5.0.0. It provides anonymous access to view, that are marked as public with no
Public view is breaking change in NAE v5.0.0. It provides anonymous access to view, that are marked as public with only anonymous
authorization needed, users can access tasks and cases without any login or registration needed. Public view can be
implemented in case of workflow-view and task-view.
implemented in case of workflow-view, task-view and single-task-view.

## Frontend

In this manual we will define a public task view. This public task view can be accessed with
`<url>/process/:petriNetId/:caseId`. This route is set to navigate to our task view, that will send a request to
backend, search for case with defined route parameters petriNetId and caseId. Backend then returns tasks of this case
and our task view will list them. Follow these steps to implement such a public task or case view:
We can define public view components in ``nae.json`` configuration file and then
generate public view component with schematics.

- Create a component with any name you want. We will now use PublicTaskViewComponent.
- In the config JSON (where you define views parameters) you can define a new view as follows:
- the access attribute should be public
- under component, you have to define the class and path of your component.
To make work public view, you will need to define following views in ``nae.json`` ``views`` segment:

```json
{
"demo-public-view": {
"layout": {
"name": "publicTaskView",
"params": {
"allowedNets": []
"public-single-task-view": {
"layout": {
"name": "publicSingleTaskView",
"componentName": "PublicSingleTaskView"
},
"access": "public",
"navigation": {
"title": "Public view - transition"
},
"routing": {
"path": "process/:petriNetId/:caseId/:transitionId"
}
},
"component": {
"class": "PublicTaskViewComponent",
"from": "./doc/public-task-view/public-task-view.component"
},
"access": "public",
"navigation": false,
"routing": {
"path": "process/:petriNetId/:caseId"
}
}
},
"public-task-view": {
"layout": {
"name": "publicTaskView",
"componentName": "PublicTaskView"
},
"access": "public",
"navigation": {
"title": "Public view - task"
},
"routing": {
"path": "process/:petriNetId/:caseId"
}
},
"public-case-creator-view": {
"component": {
"class": "PublicTaskViewComponent",
"from": "./views/public-task-view/public-task-view.component"
},
"access": "public",
"navigation": {
"title": "Public view - case"
},
"routing": {
"path": "process/:petriNetId"
}
},
"public-workflow-view": {
"layout": {
"name": "publicWorkflowView",
"componentName": "PublicWorkflowView"
},
"access": "public",
"navigation": {
"title": "Public view - process"
},
"routing": {
"path": "process"
}
},
"public-view-resolver": {
"layout": {
"name": "publicResolver",
"componentName": "PublicResolver"
},
"access": "public",
"navigation": true,
"routing": {
"path": "public-resolver"
}
}
}
```

- In our component class, we have to define public services, resolvers and abstract components to be used instead of
default ones, and then we have to provide them to this component:

```ts
const localTaskViewServiceFactory = (factory: ConfigTaskViewServiceFactory) => {
return factory.create('demo-public-view');
};

const searchServiceFactory = (router: Router, route: ActivatedRoute, process: ProcessService,
caseResourceService: CaseResourceService, snackBarService: SnackBarService) => {
return publicSearchServiceFactory(router, route, process, caseResourceService, snackBarService);
};

const processServiceFactory = (userService: UserService, sessionService: SessionService, authService: AuthenticationService,
router: Router, publicResolverService: PublicUrlResolverService, petriNetResource: PetriNetResourceService,
publicPetriNetResource: PublicPetriNetResourceService, loggerService: LoggerService) => {
return publicFactoryResolver(userService, sessionService, authService, router, publicResolverService,
new ProcessService(petriNetResource, loggerService),
new PublicProcessService(publicPetriNetResource, loggerService));
};

const taskResourceServiceFactory = (userService: UserService, sessionService: SessionService, authService: AuthenticationService,
router: Router, publicResolverService: PublicUrlResolverService,
logger: LoggerService, provider: ResourceProvider, config: ConfigurationService,
fieldConverter: FieldConverterService) => {
return publicFactoryResolver(userService, sessionService, authService, router, publicResolverService,
new TaskResourceService(provider, config, fieldConverter, logger),
new PublicTaskResourceService(provider, config, fieldConverter, logger));
};

const caseResourceServiceFactory = (userService: UserService, sessionService: SessionService, authService: AuthenticationService,
router: Router, publicResolverService: PublicUrlResolverService,
provider: ResourceProvider, config: ConfigurationService) => {
return publicFactoryResolver(userService, sessionService, authService, router, publicResolverService,
new CaseResourceService(provider, config),
new PublicCaseResourceService(provider, config));
};

@Component({
selector: 'nae-app-public-task-view',
templateUrl: './public-task-view.component.html',
styleUrls: ['./public-task-view.component.scss'],
providers: [
ConfigTaskViewServiceFactory,
{
provide: ProcessService,
useFactory: processServiceFactory,
deps: [UserService, SessionService, AuthenticationService, Router, PublicUrlResolverService, PetriNetResourceService,
PublicPetriNetResourceService, LoggerService]
},
{
provide: TaskResourceService,
useFactory: taskResourceServiceFactory,
deps: [UserService, SessionService, AuthenticationService, Router, PublicUrlResolverService,
LoggerService, ResourceProvider, ConfigurationService, FieldConverterService]
},
{
provide: CaseResourceService,
useFactory: caseResourceServiceFactory,
deps: [UserService, SessionService, AuthenticationService, Router, PublicUrlResolverService,
ResourceProvider, ConfigurationService]
},
{
provide: SearchService,
useFactory: searchServiceFactory,
deps: [Router, ActivatedRoute, ProcessService, CaseResourceService, SnackBarService]
},
{
provide: TaskViewService,
useFactory: localTaskViewServiceFactory,
deps: [ConfigTaskViewServiceFactory]
},
]
})
export class PublicTaskViewComponent extends AbstractTaskView implements AfterViewInit {

@ViewChild('header') public taskHeaderComponent: HeaderComponent;

constructor(taskViewService: TaskViewService) {
super(taskViewService);
}

ngAfterViewInit(): void {
this.initializeHeader(this.taskHeaderComponent);
}

logEvent(event: TaskEventNotification) {
console.log(event);
}
}
```
Then run ``@netgrif/schematics:create-view``, which will lookup ``nae.json`` for missing
views, and will generate them from config.

That's all for frontend.

Expand Down

0 comments on commit a9e4841

Please sign in to comment.