diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 0bd5aacf956..6679165c0b7 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -7,8 +7,6 @@ * [Event queue](events/event_queue.md) * [Search]() * [Elastic](search/elastic_mapping.md) - * [Filter](search/filter.md) - * [Import / Export](search/filter_import_export.md) * [Permissions]() * [User list](roles/userlist.md) * [Permissions](roles/permissions.md) diff --git a/docs/search/filter.md b/docs/search/filter.md deleted file mode 100644 index 0d9924921b2..00000000000 --- a/docs/search/filter.md +++ /dev/null @@ -1,842 +0,0 @@ -# Developers guide to the Filter process - -This document contains information about the Filter process and the API provided by the application engine for -interacting with the instances of the Filter process. - -## Filter data variable - -This data variable stores a -generated [elastic query string query](https://www.elastic.co/guide/en/elasticsearch/reference/6.6/query-dsl-query-string-query.html) -as it’s value. - -It has two additional properties that store the metadata necessary for the reconstruction of a filter. - -* _**allowedNets**_ - similar to the case ref data variable type, a list of identifiers of “allowed nets“ is stored in - the filter field. The stored nets represent the nets that can be used to construct search queries within the advanced - search component. -* _**filterMetadata**_ - data necessary for reconstructing the state of the advanced search component. The backend - currently does not provide any utility methods for construction of the metadata object. An interface for this object - can be found in - the [documentation](https://developer.netgrif.com/projects/engine-frontend/5.4.1/nae/docs/interfaces/FilterMetadata.html) - . - -Beware that while a filter field does not throw an error when displayed in editable mode and changes can be made to its -frontend representation, these changes are not propagated to backend and do not fire a set data event on the field. -Because of this we recommend only using filter fields in visible mode, to display their values set by the frontend -filter API. - -Neither title nor any other meta attribute of the filter field (such as description) is displayed as part of the filter -field component. - -![Filter field editable](../_media/search/Filter-processes-guide-field-example-editable.png) - -*an editable filter field* - -![Filter field visible](../_media/search/Filter-processes-guide-field-example-visible.png) - -*a visible filter field* - -![Filter field immediate](../_media/search/Filter-processes-guide-field-example-immediate.png) - -*an immediate filter field displayed on a panel* - -## Filter process - -The engine filter process is located under `resources/petriNets/engine-processes/filter.xml` - -![Filter process](../_media/search/Filter-processes-guide-filter-process.png) - -The process is relatively simple. It stores and makes accessible the data necessary for the persistence of filters -created by users of the application engine. All the process logic, the model contains is focussed solely on the creation -process of the filter before it reaches its "initialized" state denoted by `p2`. - -The process can be overridden by the developers, by placing a net with the same file name and identifier into the -location specified above. The process defines a “process interface” that must remain unchanged when overriding the -process for the frontend APIs that connects to the process to work correctly. Attributes of the process that are part of -the “process interface“ and must remain unchanged will be highlighted. - -### Filter process interface - -#### Data variables - -##### Filter - -```xml - - filter - Filter - -``` - -This field contains the saved filter. - -It must be `immediate`, have the ID `filter` and be of type `filter`. - -##### Filter type - -```xml - - filter_type - Filter type - - - - - -``` - -This data variable stores the type of the filter stored in the filter field of the filter process. The keys are used for -filtering of the filter processes. - -It must be `immediate`, have the ID `filter_type` and be of type `enumeration_map`. The available options must have the -keys `Case` and `Task`. The values associated with these keys are not specified by the Filter process interface and can -therefore be freely overridden. - -##### Filter visibility - -```xml - - visibility - Filter visibility - - - - - public - -``` - -This data variable can be used for filtering of the filter processes based on some internal rules. The application -engine queries this variable when listing filter during navigation menu customisation and during filter export. Only -public and private filters authored by the logged user are offered as options during these selection processes. - -No universal restriction is applied to the search queries on these instances, however. The developer must ensure that no -inappropriate filters become available to the user during any search at their own discretion. The queries used by the -application engine can be overridden, by extending the `IUserFiltersSearchService` interface. - -It must be `immediate`, have the ID `visibility` and be of type `enumeration_map`. The available options must have the -keys `public` and `private`. The values associated with these keys are not specified by the Filter process interface and -can therefore be freely overridden. - -##### Origin ViewId - -```xml - - origin_view_id - Origin ViewId - -``` - -The viewId of the view where the filter was created is stored in this data variable. -Is only set if the filter originates from a view with an in-app filter. - -When the field is set an action is triggered, that resolves the parent filter (if any) and populates the data variables -that are responsible for displaying the parent filter with the appropriate values. - -It must be `immediate`, have the ID `origin_view_id` and be of type `text`. - -##### Parent filter Id - -```xml - - parent_filter_id - parent filter ID - -``` - -The case ID of the parent filter case (if any). Is only set if the filter originates from a different filter case (usually via configurable menu). - -When the field is set an action is triggered, that resolves the parent filter (if any) and populates the data variables -that are responsible for displaying the parent filter with the appropriate values. - -It must have the ID `parent_filter_id` and be of type `text`. - -##### Filter name - -```xml - - new_title - Filter name - -``` - -This data variable is used to change the title of the newly created filter case according to the wishes of the user. - -The Filter process interface does not specify any restrictions for this data variable, it can be freely overridden or -omitted. - -##### I18n filter name - -```xml - - i18n_filter_name - - -``` - -Contains the name of the filter with locale specific translations. Its value is used to generate configurable group -navigation menu entry titles. - -It must be `immediate`, have the ID `i18n_filter_name` and be of type `enumeration`. - -The previously mentioned `new_title` data variable has a set action, that pushes its value into this variable. Since -the `new_title` variable is a plain text field, a `I18nString` object with only its default value set is put into this -variable. This field however does support translations, so localised menu entries can be created, or their names changed -trough actions. - -##### Filter case id - -```xml - - filter_case_id - - -``` - -This variable is set during the case creation and stores the ID of this case. Since the frontend integration accesses -the filter process mostly trough tasks, this field can be referenced in any of those tasks to grant direct access to the -case ID, without having to execute an extra search query. The frontend integration does not use this variable currently, -but it can be used in custom integrations. - -The Filter process interface does not specify any restrictions for this data variable, it can be freely overridden or -omitted. - -##### And me - -```xml - - and_me - AND - -``` - -Stores the translated text of the word "AND" in order to create a visual representation of the true filter content. More -information about this can be found in the transition section. - -The Filter process interface does not specify any restrictions for this data variable, it can be freely overridden or -omitted. - -##### And view - -```xml - - and_view - AND - -``` - -Similarly to the `and_me` data variable, this too stores the translated text of the word "AND" in order to create a -visual representation of the true filter content. - -This variable is referenced in the action associated with the `origin_view_id` data variable and on the `view_filter` -and `view_as_ancestor` transitions. If it were to be removed this must be taken into the account. - -The Filter process interface does not specify any restrictions for this data variable, it can be freely overridden or -omitted. - -##### Parent filter task ref - -```xml - - taskref_and_parent - - -``` - -Similarly to the `and_view` data variable, this too is used to create the visual representation of the true filter -content, because it stores a reference to the task in the parent filter process that contains the true visualisation of -the parent filter. - -Just like the `and_view` data variable, this too is referenced in the action associated with the `origin_view_id` data -variable and on the `t1` and `t2` transitions. If it were to be removed this must be taken into the account. - -The Filter process interface does not specify any restrictions for this data variable, it can be freely overridden or -omitted. - -##### Trimmed origin view id - -```xml - - trimmed_origin_view_id - Filter from view with ID - -``` - -Similarly to the `and_view` data variable, this too is used to create the visual representation of the true filter -content, because it stores a trimmed version of the origin view id, that does not contain any tabbed view identifiers. - -Just like the `and_view` data variable, this too is referenced in the action associated with the `origin_view_id` data -variable and on the `t1` and `t2` transitions. If it were to be removed this must be taken into the account. - -The Filter process interface does not specify any restrictions for this data variable, it can be freely overridden or -omitted. - -##### Is imported - -```xml - - is_imported - - 0 - -``` - -This is the reference value for variable arc to decide, if the filter is imported by the Import filter process or is -automatically created by the backend. When set, it sets the value of the `is_not_imported` data variable to `0`. - -It must have the ID `is_imported`, be of type `number` and have the initial value `0`. - -##### Is not imported - -```xml - - is_not_imported - - 1 - -``` - -This is the reference value for the alternative variable arc to decide, if the filter is imported by the Import filter -process or is automatically created by the backend. - -It must have the ID `is_not_imported`, be of type `number` and have the initial value `1`. - -##### Missing allowed nets - -```xml - - missing_allowed_nets - Missing processes - List of missing processes for current filter - - htmltextarea - - -``` - -The purpose of this textarea is to show the list of missing allowed nets for the current (imported) filter. It is -displayed in `import_filters` transition while importing new filter from XML. - -It must have the ID `missing_allowed_nets`, be of type `text` and have the component `htmltextarea`. - -##### Missing nets translations - -```xml - - missing_nets_translation - - - - - - - -``` - -The purpose of this map filed is to translate the message in the `missing_allowed_nets` HTML textarea, because the -message in the textarea is dynamically generated depending on the active locale. - -It must have the ID `missing_nets_translation` and be of type `enumeration_map`. - -##### My full filter - -```xml - - my_full_filter - - -``` - -This task ref holds a reference to the view_filter transition and is displayed in all tasks that should show the contents of the saved filter. - -It is not referenced by anything outside the process, so it can be freely modified, provided all the internal references are compatible. - -#### Functions - -##### initializeMyFullFilterTaskRef - -```xml - - { - com.netgrif.application.engine.petrinet.domain.dataset.TaskField myFullFilter - -> - change myFullFilter value {return [findTask({it.caseId.eq(useCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId]} - } - -``` - -This utility process-scoped function is used to set the value of the `my_full_filter` task ref data variable. - -It is called in a finish-post action of both the `frontend_create` and `auto_create` transitions, -since their execution makes the searched transition (`view_filter`) executable. - -#### Roles - -##### System - -The system role is used to hide the `view_filter` and `view_as_ancestor` tasks from the user. - -The other transitions executed by the system are never searched for by the frontend API and therefore don't need to have this role assigned to them. - -#### Transitions - -The net consists of seven transitions. **Set filter metadata** and **create new filter** are used when creating filter -from frontend filter API. -**Automated new** is used, when creating filter from backend automatically. **Import filter** transition is used when -importing filters in the -_import\_filters_ process. The last three transitions **Details**, **View filter** and **View as ancestor** are used to -display filter preview. - -##### Set filter metadata - -```xml - - frontend_create - - - - filter - - editable - - - - filter_type - - editable - - - - origin_view_id - - editable - - - - -``` - -This transition is executed automatically by the frontend filter API in order to set the necessary filter data into the -process instance, when a new filter is created (saved). - -It must have the transition ID `frontend_create`. - -It must contain 4 data fields that are set via an API request: - -* `filter` -* `filter_type` -* `origin_view_id` -* `parent_filter_id` - -Custom set data requests can be sent via the frontend filter API. These requests target this task. Therefore, if you -want to set additional properties to your newly created filter instances you can do so by adding the necessary data -variables to this task and then use the frontend API to set their values. - -Once it finishes the `view_filter` and `view_as_ancestor` tasks become executable. -An action is bound to the finish of this transition, that sets the reference of the `my_full_filter` task ref. - -##### Create new filter - -```xml - - newFilter - auto - - - - my_full_filter - - visible - - - - - - visibility - - editable - required - - - - new_title - - editable - required - - - - -``` - -This transition is displayed to the user in the side menu when a new filter case instance is created (a filter is saved) -through the frontend filter API. - -It can reference any filter data variables. The default implementation references, the filter and its type in visible -mode (they were set in the previous step), an editable visibility choice and an editable text field for setting the new -filter case title (via a finish action). - -It must have the transition ID `newFilter`. - -##### Automated new filter - -```xml - - auto_create - - - - filter - - editable - - - - filter_type - - editable - - - - visibility - - editable - - - - origin_view_id - - editable - - - - -``` - -This transition is executed by the `DefaultFiltersRunner`, in order to set the data present in the previous two -transitions with a single `setData` operation. - -It must have the transition ID `auto_create`. - -It must contain 5 data fields that are set via a `setData` API call. - -* `filter` -* `filter_type` -* `origin_view_id` -* `parent_filter_id` -* `visibility` - -Once it finishes the `view_filter` and `view_as_ancestor` tasks become executable. -An action is bound to the finish of this transition, that sets the reference of the `my_full_filter` task ref. - -##### Import filter - -```xml - - import_filter - - - - new_title - - editable - - - - filter_type - - visible - - - - visibility - - editable - - - - missing_allowed_nets - - hidden - - - - - - my_full_filter - - visible - - - - -``` - -This transition is used in the `import_filters` process to allow editing of filter name and filter visibility when -importing a new filter. - -It must have the transition ID `import_filter`. - -It should contain at least these data fields to display to the user which filter is being imported and allow them to -change some fundamental filter properties: - -* `new_title` (editable) -* `filter_type` (visible) -* `visibility` (editable) -* `my_full_filter` (visible) -* `missing_allowed_nets` (hidden) - made visible by the import action if some nets are missing - -##### Details - -```xml - - t2 - - - - filter - - visible - - - - filter_type - - visible - - - - visibility - - visible - - - - -``` - -This transition makes the filter metadata accessible to the users of the application. - -The Filter process interface does not specify any restrictions for this data variable, it can be freely overridden or -omitted. Beware however, that it is referenced by the `origin_view_id` actions. This must be taken into the account when -omitting this transition. - -##### View filter - -```xml - - view_filter - - - - filter - - visible - - - - filter_case_id - - hidden - - - - origin_view_id - - forbidden - - - - taskref_and_parent - - visible - - - - - DataGroup_1 - grid - - and_view - - forbidden - - - - trimmed_origin_view_id - - forbidden - - - - -``` - -This transition displays the true content of the filter represented by the process. It can be task-reffed to show a -referenced filter somewhere (such as in the configurable group navigation entries and filter previews). In addition to -the filter field itself the ancestor filters are displayed here as well. Each of them is prefixed with an AND text to -indicate that they are combined with the original filter with the **and** operator. - -If the root of the filter chain is a filter process (indicated by its `parent_filter_id` having a non-empty value) -the root filters content will be the last entry displayed. If the root is a frontend filter -(indicated by its `origin_view_id` field being set to a non-empty string) the last entry will -contain a text indicating the view from which the filter originates. The displayed view ID excludes any tab suffixes. - -If the filter does not originate from a view its `origin_view_id` field must have its behavior set to `forbidden`, -so that the frontend parsing mechanism won't find false positives during the interpretation of the filter. - -It must have the transition ID `view_filter`. - -It must contain 1 data field: - -* `filter` - -##### View as ancestor - -```xml - - view_as_ancestor - - - - and_me - - visible - - - - filter - - visible - - - - taskref_and_parent - - visible - - - - - DataGroup_1 - grid - - and_view - - forbidden - - - - trimmed_origin_view_id - - forbidden - - - - -``` - -Contains the same information as the View filter task, but every row is prefixed with an AND text (including the first -row that contains the filter field of this case). - -This task is referenced when resolving ancestor filters from the immediate children of this filter. - -## Backend filter API - -Since filters are implemented as Petriflow processes, they share the same API with any other process. The old filter -related services, controllers and other classes have been deprecated in the 5.4.0 release and should no longer be used. - -There are a few things to keep in mind when working with filters. - -### Using filter fields for filtering of cases and tasks - -You can use the value and other attributes of a filter field to create database queries. - -When doing so, make sure to check if the filter has the appropriate type (that is only use Case filters to filter cases -and Task filters to filter tasks). - -The value attribute of a filter field is -an [elastic query string query](https://www.elastic.co/guide/en/elasticsearch/reference/6.6/query-dsl-query-string-query.html) ( -as mentioned above) and therefore cannot be used to filter entries from the Mongo database. It can however be turned -into a `CaseSearchRequest` class instance, by populating the `query` attribute with the filter field value. This object -can then be passed to the `ElasticCaseService` to find the cases that match the query. If you want to search for task -instances then analogous classes and services exist. - -### Actions API - -Filter fields have only a limited support in the actions API. - -Only their value can be changed with the `change` action and this change is NOT propagated to the other filter field -attributes (allowedNets and filterMetadata). Since these two attributes are the important part when restoring an -advanced search component state on the frontend it can easily lead to “desynchronisation“ of these values. Changing -these values should therefore be done cautiously. - -### Set data method - -The set data method of the `TaskDataService` can be used to modify all the attributes of a filter field. All of them -must be set at the same time, any missing attributes will have its value set to `null`. - -### DefaultFiltersRunner - -This runner contains utility methods that can be used to create default system filter process instances. The author of -these filters will be the system user. - -## Frontend filter API - -Since saved filters are cases you should use the existing API for interacting with cases. Utility methods exist for some -operations. You should keep in mind however that, the frontend library does not provide a full filter persistence and -management implementation, only the building blocks for creating one, therefore you must implement it on your own -according to your wishes. An overview of these building blocks can be found in the following sections. - -### Filter constants - -The -enum [UserFilterConstants](https://developer.netgrif.com/projects/engine-frontend/latest/nae/docs/miscellaneous/enumerations.html#UserFilterConstants) -contains identifiers and IDs of all parts of the filter process referenced by the frontend filters API. - -### UserFiltersService - -The [UserFiltersService](https://developer.netgrif.com/projects/engine-frontend/latest/nae/docs/injectables/UserFiltersService.html) -contains the API for saving, loading and deleting filter process instances. - -The search component contains buttons that trigger the save and load methods, so you do not have to use this service -directly, but if you wish to create your own user interface you can re-use the implementation provided by this service. - -Injection tokens are available for the configuration of the side menu components used to save and load -filters (`NAE_SAVE_FILTER_COMPONENT` and `NAE_LOAD_FILTER_COMPONENT`). An injection token is also available for -configuring the filter that filters the filter process instances displayed when loading a filter (`NAE_FILTERS_FILTER`). - -### SearchComponent - -The [SearchComponent](https://developer.netgrif.com/projects/engine-frontend/latest/nae/docs/classes/AbstractSearchComponent.html) -is a wrapper for the two search mode components (fulltext and advanced) -these components can be used independently of each other and the search component combines them into one and adds -various control elements to them. - -The search component has two outputs - `filterLoaded` and `filterSaved`. These emit data related to either the saved -filter, or the selected filter in the load pop-up. The developers must process these outputs in order to implement fully -functional filter management. - -The component also has na input - `additionalFilterData`. This input can be used to modify the content of the set data -request that is sent by the `UserFiltersService`, when a new filter is created. This way a less invasive option is -available when overriding the default filter process and adding additional metadata necessary for your implementation of -filter management. - -An injection token is available for the configuration of the search component - `NAE_SEARCH_COMPONENT_CONFIGURATION`. It -provides -a [SearchComponentConfiguration](https://developer.netgrif.com/projects/engine-frontend/latest/nae/docs/interfaces/SearchComponentConfiguration.html) -object that can be used to hide many elements of the search component (buttons mostly). This way you can remove the save -and/or load filter buttons and therefore not allow the users to persist filters in some specific views. - -### SearchService - -The [SearchService](https://developer.netgrif.com/projects/engine-frontend/latest/nae/docs/injectables/SearchService.html) -provides two complementary methods - `createPredicateMetadata` and `loadFromMetadata`. These can be used to populate the -search service with a predicate stored inside a filter field (`filterMetadata` attribute). If an advanced search -component is connected to the search service, then it will automatically display the loaded predicate. - -### FilterExtractionService - -The [FilterExtractionService](https://developer.netgrif.com/projects/engine-frontend/latest/nae/docs/injectables/FilterExtractionService.html) -contains the functionality of extracting a frontend [Filter](https://developer.netgrif.com/projects/engine-frontend/latest/nae/docs/classes/Filter.html) -instance from the data of a configurable navigation entry task. \ No newline at end of file diff --git a/docs/search/filter_import_export.md b/docs/search/filter_import_export.md deleted file mode 100644 index cd98e559025..00000000000 --- a/docs/search/filter_import_export.md +++ /dev/null @@ -1,172 +0,0 @@ -# Filter import/export - -## User guide - -This guide is aimed at application users that wish to know, how to import/export selected filters from/to application. -If you are developer that wishes to know more about the implementation and various ways the system can be interacted -with, you can find this information in the Developer guide of filter import/export. - -### Overview - -Every user in the application have option to import/export filters. For every user in application case for import -filters and also case for export filters exists as shown on the next image. - -
- -![alt text](../_media/search/import_export_cases.png "Import and Export cases") - -
- -### Processes - -#### Export filters - -After user opens **Export filters USERNAME** case, task to export filters is displayed. The task consists of three -fields, from which only two are initially displayed to user. - -
- -![alt text](../_media/search/export_filters_1.png "Export of filters initial") - -
- -First field is multi choice field, which allows user to select multiple filters, which he wants to export. Filters that -are displayed in this multi choice are all **public** filters in the application (filters which can be created by other -users) and also all **private** filters of currently logged user. After user selects filters which he wants to export -and clicks on the **Export filters** button, the third field is displayed. - -
- -![alt text](../_media/search/export_filters_2.png "Exported filters file") - -
- -This field holds exported xml file, which contains exported filters in the custom xml format. User can download this -file by clicking on its name. This file can be later used to import filters into the application. Users should never -create or modify these files on their own, because of the complexity of filters format inside xml file. - -#### Import filters - -After user opens **Import filters USERNAME** case, task to import filters is displayed. The task consists of two fields, -which are initially displayed to user and after these two fields there is one section for every imported filter. - -
- -![alt text](../_media/search/import_filters_1.png "Import of filters initial") - -
- -First field is file field, where user should upload xml file, that contains exported filters. After user uploads this -xml file and clicks on **Import filters** button, application validate uploaded file against schema, which doesn't allow -upload of files in incorrect format. If format of uploaded file is correct, application initialize creation of filters -and displays these filters under initially displayed fields. - -
- -![alt text](../_media/search/import_filters_2.png "Imported filters displayed") - -
- -Each section after horizontal line represents one imported filter. User can change two properties for each imported -filter. First one is filter name and the second one is visibility of the filter. User can also see type of the filter ( -if the filter is for tasks or for cases) and also filter preview, so he can know what it is filtering. - -In some situation, imported filter have dependency on some processes. To correctly display preview of filter and further -correct function of filter, all these processes need to be uploaded in application. If some of these processes are -missing, list of missing processes is displayed inside textarea as shown on next image. - -
- -![alt text](../_media/search/import_filters_3.png "Missing process") - -
- -When user is satisfied with imported filters, their names and visibility, he can confirm creation of these filters by -pressing **FINISH** button on the bottom right. If the imported filters are not according to his ideas, he can abort -further creation of these filters by pressing **CANCEL** button or deleting uploaded xml file from file field. - -## Developer guide - -This guide is aimed at developers that wish to know the implementation detail of filter import/export, so they can -interact with or override its implementation. If you are application user and wish to know how to use the options -available to you read the User guide of filter import/export. Please read **Filter process guide** before u start -reading this one, because of some references on this process. - -### Overview - -The filter import and export consists of two processes, which are independent of each other. Names of processes are -self-explaining: - -- **Export of filters** - serves for export of filters into xml file `export_filters.xml` -- **Import of filters** - serves for import of filters from xml file `import_filters.xml` - -New schema, which describes format of xml file for exported filters, were introduced -`filter_export_schema.xml`. All imported xml files containing filters are validated against this schema to ensure -filters will be correctly created and working. Also, new exception class for incorrect xml file format of imported -filters was created to throw error after validating xml file against schema `IllegalFilterFileException`. - -Multiple classes were added to support serialization and deserialization of filters. These classes are: - -- Configuration -- FilterImportExport -- FilterImportExportList -- FilterMetadataExport -- Predicate -- PredicateArray -- PredicateValue -- CustomFilterDeserializer - -`ActionDelegate` have two new functions, which support filters import/export: -`exportFilters(Collection filtersToExport)` and `importFilters()`. Also, new service `FilterImportExportService` -which is called by these two functions was created and which performs most functionality in importing and exporting -functions. - -When creating new user, case for importing filters and also case for exporting filters is created for this user. - -Also, new property was added into `application.properties`, with name `nae.filter.export.file-name`, which defines name -of xml file that contains exported filters. This property has default string value of **filters.xml**. - -When filters are exported, all of their ancestors are exported as well. If the exported filters have common ancestors, -the ancestors are only exported once. The relationships between filters are reconstructed on import based on the -exported filters case Ids. It is assumed that parents precede their children in the imported file -(the exported file is generated in this way). If a filter cannot find its parent on import the connection will -be severed and an error will be logged. - -### Processes - -#### Export filters - -Export process consists of one task `exportFilter`, which carry out whole exporting of filters. Process and also the -only task consist of three data fields. First one is `exportable_filters`, which is **multichoice_map** that displays -all filters, that are exportable by currently logged user. List is loaded from `ActionDelegate` -method `findAllFilters()` and returns all filter cases, that are public and created by any user or that are private and -created by currently logged user. - -After selecting filters to export and clicking on second data field **button** with id `export_btn`, the -method `exportFilters()` from `ActionDelegate` -is called. This method serialize selected filters into xml file and put this file into third **file** field with -id `export_file`. - -Export filters can be run any number of times so the user can export any number of filters in selected combinations into -any number of xml files. - -#### Import filters - -Import process also consists of one task `importFilter`, which carry out whole importing of filters. There are also just -three data fields in this process. First one is **file** field `upload_file` that serves for upload of xml file with -filters. After uploading this file and clicking on the next **button** field `import_file`, the `importFilters()` method -from `ActionDelegate` is called, that validates uploaded xml file against xsd schema. - -- If file is valid, method creates **Filter** cases via **Automated new filter** task and move them into **Import - filter** task. Method returns list of **Import filter** task ids, that are set as value for **taskRef** - field `imported_filters`, so the user can update some values of these filters. -- If file is not valid, error message is thrown. - -Pressing **FINISH** button in this task moves imported filters into state, where they can be added into group -navigation. - -Pressing **CANCEL** button or changing value to `upload_file` deletes created filters, so there will not be unworkable -filters saved in the application database. - -As well as export filters, import filters can be run any number of times, so user can upload how many filters as he -wants. diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/CaseFilterField.groovy b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/CaseFilterField.groovy new file mode 100644 index 00000000000..38e32db0ee1 --- /dev/null +++ b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/CaseFilterField.groovy @@ -0,0 +1,23 @@ +package com.netgrif.application.engine.petrinet.domain.dataset + +import org.springframework.data.mongodb.core.mapping.Document + +@Document +class CaseFilterField extends Field { + + CaseFilterField() { + super() + } + + @Override + FieldType getType() { + return FieldType.CASE_FILTER + } + + @Override + Field clone() { + CaseFilterField clone = new CaseFilterField() + super.clone(clone) + return clone + } +} diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FieldType.groovy b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FieldType.groovy index 0b96783f52c..53ed4407918 100644 --- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FieldType.groovy +++ b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FieldType.groovy @@ -21,7 +21,9 @@ enum FieldType { DATETIME("dateTime"), BUTTON("button"), TASK_REF("taskRef"), - FILTER("filter"), + CASE_FILTER("caseFilter"), + TASK_FILTER("taskFilter"), + PROCESS_FILTER("processFilter"), I18N("i18n"), STRING_COLLECTION("stringCollection") diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FilterField.groovy b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FilterField.groovy deleted file mode 100644 index a0102f21cc5..00000000000 --- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/FilterField.groovy +++ /dev/null @@ -1,47 +0,0 @@ -package com.netgrif.application.engine.petrinet.domain.dataset - -import org.springframework.data.mongodb.core.mapping.Document - -@Document -class FilterField extends FieldWithAllowedNets { - - /** - * Serialized information necessary for the restoration of the advanced search frontend GUI. - * - * Backend shouldn't need to interact with this attribute - */ - private Map filterMetadata - - FilterField() { - super() - allowedNets = new ArrayList<>() - filterMetadata = new HashMap<>() - } - - FilterField(List allowedNets) { - super(allowedNets) - filterMetadata = new HashMap<>() - } - - @Override - FieldType getType() { - return FieldType.FILTER - } - - @Override - Field clone() { - FilterField clone = new FilterField() - super.clone(clone) - clone.filterMetadata = this.filterMetadata - - return clone - } - - Map getFilterMetadata() { - return filterMetadata - } - - void setFilterMetadata(Map filterMetadata) { - this.filterMetadata = filterMetadata - } -} diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/ProcessFilterField.groovy b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/ProcessFilterField.groovy new file mode 100644 index 00000000000..35d238becf4 --- /dev/null +++ b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/ProcessFilterField.groovy @@ -0,0 +1,23 @@ +package com.netgrif.application.engine.petrinet.domain.dataset + +import org.springframework.data.mongodb.core.mapping.Document + +@Document +class ProcessFilterField extends Field { + + ProcessFilterField() { + super() + } + + @Override + FieldType getType() { + return FieldType.PROCESS_FILTER + } + + @Override + Field clone() { + ProcessFilterField clone = new ProcessFilterField() + super.clone(clone) + return clone + } +} diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/TaskFilterField.groovy b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/TaskFilterField.groovy new file mode 100644 index 00000000000..a54c5421b59 --- /dev/null +++ b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/TaskFilterField.groovy @@ -0,0 +1,23 @@ +package com.netgrif.application.engine.petrinet.domain.dataset + +import org.springframework.data.mongodb.core.mapping.Document + +@Document +class TaskFilterField extends Field { + + TaskFilterField() { + super() + } + + @Override + FieldType getType() { + return FieldType.TASK_FILTER + } + + @Override + Field clone() { + TaskFilterField clone = new TaskFilterField() + super.clone(clone) + return clone + } +} diff --git a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy index 26791594b3e..5fd5c9d022e 100644 --- a/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy +++ b/src/main/groovy/com/netgrif/application/engine/petrinet/domain/dataset/logic/action/ActionDelegate.groovy @@ -26,14 +26,14 @@ import com.netgrif.application.engine.mail.interfaces.IMailService import com.netgrif.application.engine.menu.domain.FilterBody import com.netgrif.application.engine.menu.domain.MenuItemBody import com.netgrif.application.engine.menu.domain.MenuItemConstants -import com.netgrif.application.engine.menu.domain.configurations.TabbedCaseViewBody -import com.netgrif.application.engine.menu.domain.configurations.TabbedTaskViewBody +import com.netgrif.application.engine.menu.domain.configurations.CaseViewBody +import com.netgrif.application.engine.menu.domain.configurations.TaskViewBody import com.netgrif.application.engine.menu.domain.configurations.ViewBody import com.netgrif.application.engine.menu.domain.dashboard.DashboardItemBody import com.netgrif.application.engine.menu.domain.dashboard.DashboardManagementBody -import com.netgrif.application.engine.menu.services.interfaces.DashboardItemService -import com.netgrif.application.engine.menu.services.interfaces.DashboardManagementService -import com.netgrif.application.engine.menu.services.interfaces.IMenuItemService +import com.netgrif.application.engine.menu.service.interfaces.DashboardItemService +import com.netgrif.application.engine.menu.service.interfaces.DashboardManagementService +import com.netgrif.application.engine.menu.service.interfaces.IMenuItemService import com.netgrif.application.engine.orgstructure.groups.interfaces.INextGroupService import com.netgrif.application.engine.pdf.generator.config.PdfResource import com.netgrif.application.engine.pdf.generator.service.interfaces.IPdfGenerator @@ -49,8 +49,6 @@ import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetServi import com.netgrif.application.engine.petrinet.service.interfaces.IProcessRoleService import com.netgrif.application.engine.petrinet.service.interfaces.IUriService import com.netgrif.application.engine.rules.domain.RuleRepository -import com.netgrif.application.engine.startup.DefaultFiltersRunner -import com.netgrif.application.engine.startup.FilterRunner import com.netgrif.application.engine.startup.ImportHelper import com.netgrif.application.engine.utils.FullPageRequest import com.netgrif.application.engine.workflow.domain.Case @@ -162,18 +160,9 @@ class ActionDelegate { @Autowired Scheduler scheduler - @Autowired - IUserFilterSearchService filterSearchService - @Autowired IConfigurableMenuService configurableMenuService - @Autowired - IMenuImportExportService menuImportExportService - - @Autowired - IFilterImportExportService filterImportExportService - @Autowired IExportService exportService @@ -672,7 +661,7 @@ class ActionDelegate { saveChangedChoices(field, targetCase, targetTask) }, allowedNets : { cl -> - if (!(field instanceof CaseField)) // TODO make this work with FilterField as well + if (!(field instanceof CaseField)) return def allowedNets = cl() @@ -1395,25 +1384,6 @@ class ActionDelegate { return new DynamicValidation(rule, message) } - List findFilters(String userInput) { - return filterSearchService.autocompleteFindFilters(userInput) - } - - List findAllFilters() { - return filterSearchService.autocompleteFindFilters("") - } - - FileFieldValue exportFilters(Collection filtersToExport) { - if (filtersToExport.isEmpty()) { - return null - } - return filterImportExportService.exportFiltersToFile(filtersToExport) - } - - List importFilters() { - return filterImportExportService.importFilters() - } - File exportCasesToFile(Closure predicate, String pathName, ExportDataConfig config = null, int pageSize = exportConfiguration.getMongoPageSize()) { File exportFile = new File(pathName) @@ -1556,318 +1526,6 @@ class ActionDelegate { return findTasks(requests, loggedUser, page, pageSize, locale, isIntersection) } - List findDefaultFilters() { - if (!createDefaultFilters) { - return [] - } - return findCases({ it.processIdentifier.eq(FilterRunner.FILTER_PETRI_NET_IDENTIFIER).and(it.author.id.eq(userService.system.stringId)) }) - } - - /** - * Creates filter instance of type {@value DefaultFiltersRunner#FILTER_TYPE_CASE} - * - * @param title filter case title - * @param query elastic query for the view - * @param icon filter case icon - * @param allowedNets List of process identifiers - * @param visibility Possible values: {@value DefaultFiltersRunner#FILTER_VISIBILITY_PRIVATE} or {@value DefaultFiltersRunner#FILTER_VISIBILITY_PUBLIC} - * @param filterMetadata metadata for filter. If no value is provided, then default value is used: {@link #defaultFilterMetadata(String)} - * - * @return created {@link Case} instance of filter - */ - @NamedVariant - Case createCaseFilter(def title, String query, List allowedNets, - String icon = "", String visibility = DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE, def filterMetadata = null) { - return createFilter(title, query, DefaultFiltersRunner.FILTER_TYPE_CASE, allowedNets, icon, visibility, filterMetadata) - } - - /** - * Creates filter instance of type {@value DefaultFiltersRunner#FILTER_TYPE_TASK} - * - * @param title filter case title - * @param query elastic query for the view - * @param icon filter case icon - * @param allowedNets List of process identifiers - * @param visibility Possible values: {@value DefaultFiltersRunner#FILTER_VISIBILITY_PRIVATE} or {@value DefaultFiltersRunner#FILTER_VISIBILITY_PUBLIC} - * @param filterMetadata metadata for filter. If no value is provided, then default value is used: {@link #defaultFilterMetadata(String)} - * - * @return created {@link Case} instance of filter - */ - @NamedVariant - Case createTaskFilter(def title, String query, List allowedNets, - String icon = "", String visibility = DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE, def filterMetadata = null) { - return createFilter(title, query, DefaultFiltersRunner.FILTER_TYPE_TASK, allowedNets, icon, visibility, filterMetadata) - } - - /** - * Creates filter instance. - * - * @param title filter case title - * @param query elastic query for the view - * @param type Filter type. Possible values: {@value DefaultFiltersRunner#FILTER_TYPE_CASE} or {@value DefaultFiltersRunner#FILTER_TYPE_TASK} - * @param icon filter case icon - * @param allowedNets List of process identifiers - * @param visibility Possible values: {@value DefaultFiltersRunner#FILTER_VISIBILITY_PRIVATE} or {@value DefaultFiltersRunner#FILTER_VISIBILITY_PUBLIC} - * @param filterMetadata metadata for filter. If no value is provided, then default value is used: {@link #defaultFilterMetadata(String)} - * - * @return created {@link Case} instance of filter - */ - @NamedVariant - Case createFilter(def title, String query, String type, List allowedNets, - String icon, String visibility, def filterMetadata) { - FilterBody body = new FilterBody() - body.setTitle((title instanceof I18nString) ? title : new I18nString(title as String)) - body.setQuery(query) - body.setType(type) - body.setAllowedNets(allowedNets) - body.setIcon(icon) - body.setVisibility(visibility) - body.setMetadata(filterMetadata) - return menuItemService.createFilter(body) - } - - /** - * Changes data of provided filter instance. These attributes can be changed: - *
    - *
  • changeFilter filter query { "processIdentifier:"my_process_id" } - *
  • changeFilter filter visibility { "private" } - *
  • changeFilter filter allowedNets { ["my_process_id1","my_process_id2"] } - *
  • changeFilter filter filterMetadata { [
    -     "searchCategories"       : [],
    -     "predicateMetadata"      : [],
    -     "filterType"             : "Case",
    -     "defaultSearchCategories": true,
    -     "inheritAllowedNets"     : false
    -     ] }
    - *
  • changeFilter filter title { new I18nString("New title") } - *
  • changeFilter filter title { "New title" } - *
  • changeFilter filter icon { "filter_alt" } - *
  • changeFilter filter uri { "/my_node1/my_node2" } - *
- * @param filter {@link Case} instance of filter - */ - def changeFilter(Case filter) { - [query : { cl -> - updateFilter(filter, [ - (DefaultFiltersRunner.FILTER_FIELD_ID): [ - "type" : "enumeration_map", - "value": cl() as String - ] - ]) - }, - visibility : { cl -> - updateFilter(filter, [ - (DefaultFiltersRunner.FILTER_VISIBILITY_FIELD_ID): [ - "type" : "enumeration_map", - "value": cl() as String - ] - ]) - }, - allowedNets : { cl -> - String currentQuery = workflowService.findOne(filter.stringId).dataSet[DefaultFiltersRunner.FILTER_FIELD_ID].value - updateFilter(filter, [ - (DefaultFiltersRunner.FILTER_FIELD_ID): [ - "type" : "filter", - "value" : currentQuery, - "allowedNets": cl() as List - ] - ]) - }, - filterMetadata: { cl -> - String currentQuery = workflowService.findOne(filter.stringId).dataSet[DefaultFiltersRunner.FILTER_FIELD_ID].value - updateFilter(filter, [ - (DefaultFiltersRunner.FILTER_FIELD_ID): [ - "type" : "filter", - "value" : currentQuery, - "filterMetadata": cl() as Map - ] - ]) - }, - title : { cl -> - filter = workflowService.findOne(filter.stringId) - def value = cl() - filter.setTitle(value as String) - filter.dataSet[DefaultFiltersRunner.FILTER_I18N_TITLE_FIELD_ID].value = (value instanceof I18nString) ? value : new I18nString(value as String) - workflowService.save(filter) - }, - icon : { cl -> - filter = workflowService.findOne(filter.stringId) - def icon = cl() as String - filter.setIcon(icon) - workflowService.save(filter) - }, - uri : { cl -> - filter = workflowService.findOne(filter.stringId) - def uri = cl() as String - filter.setUriNodeId(uriService.findByUri(uri).stringId) - workflowService.save(filter) - }] - } - - /** - * deletes filter instance - * Note: do not call this method if given instance is referenced in any menu_item instance - * @param filter - * @return - */ - def deleteFilter(Case filter) { - workflowService.deleteCase(filter.stringId) - } - - /** - * create menu item for given filter instance - * @param uri - * @param identifier - unique item identifier - * @param filter - * @param groupName - * @param allowedRoles ["role_import_id": "net_import_id"] - * @param bannedRoles ["role_import_id": "net_import_id"] - * @return - */ - @Deprecated - Case createMenuItem(String uri, String identifier, Case filter, String groupName, Map allowedRoles, Map bannedRoles = [:], List caseDefaultHeaders = [], List taskDefaultHeaders = []) { - MenuItemBody body = new MenuItemBody( - uri, - identifier, - filter.dataSet[FILTER_FIELD_I18N_FILTER_NAME].value as I18nString, - null - ) - body.setAllowedRoles(collectRolesForPreferenceItem(allowedRoles)) - body.setBannedRoles(collectRolesForPreferenceItem(bannedRoles)) - body.setUseCustomView(false) - body.setUseTabbedView(true) - - body.setView(createLegacyMenuItemViews(filter, caseDefaultHeaders, taskDefaultHeaders)) - - return menuItemService.createMenuItem(body) - } - - /** - * create menu item for given filter instance - * @param uri - * @param identifier - unique item identifier - * @param filter - * @param groupName - * @param allowedRoles - * @param bannedRoles - * @return - */ - @Deprecated - Case createMenuItem(String uri, String identifier, Case filter, String groupName, List allowedRoles, List bannedRoles = [], List caseDefaultHeaders = [], List taskDefaultHeaders = []) { - MenuItemBody body = new MenuItemBody( - uri, - identifier, - filter.dataSet[FILTER_FIELD_I18N_FILTER_NAME].value as I18nString, - null - ) - - body.setAllowedRoles(collectRolesForPreferenceItem(allowedRoles)) - body.setBannedRoles(collectRolesForPreferenceItem(bannedRoles)) - body.setUseCustomView(false) - body.setUseTabbedView(true) - - body.setView(createLegacyMenuItemViews(filter, caseDefaultHeaders, taskDefaultHeaders)) - - return menuItemService.createMenuItem(body) - } - - /** - * create menu item for given filter instance - * @param uri - * @param identifier - unique item identifier - * @param filter - * @param groupName - * @param allowedRoles ["role_import_id": "net_import_id"] - * @param bannedRoles ["role_import_id": "net_import_id"] - * @param group - if null, default group is used - * @return - */ - @Deprecated - Case createMenuItem(String uri, String identifier, Case filter, Map allowedRoles, Map bannedRoles = [:], Case group = null, List caseDefaultHeaders = [], List taskDefaultHeaders = []) { - MenuItemBody body = new MenuItemBody( - uri, - identifier, - filter.dataSet[FILTER_FIELD_I18N_FILTER_NAME].value as I18nString, - null - ) - - body.setAllowedRoles(collectRolesForPreferenceItem(allowedRoles)) - body.setBannedRoles(collectRolesForPreferenceItem(bannedRoles)) - body.setUseCustomView(false) - body.setUseTabbedView(true) - - body.setView(createLegacyMenuItemViews(filter, caseDefaultHeaders, taskDefaultHeaders)) - - return menuItemService.createMenuItem(body) - } - - /** - * create menu item for given filter instance - * @param uri - * @param identifier - unique item identifier - * @param filter - * @param allowedRoles - * @param bannedRoles - * @param group - if null, default group is used - * @return - */ - @Deprecated - Case createMenuItem(String uri, String identifier, Case filter, List allowedRoles, List bannedRoles = [], Case group = null, List caseDefaultHeaders = [], List taskDefaultHeaders = []) { - MenuItemBody body = new MenuItemBody( - uri, - identifier, - filter.dataSet[FILTER_FIELD_I18N_FILTER_NAME].value as I18nString, - null - ) - - body.setAllowedRoles(collectRolesForPreferenceItem(allowedRoles)) - body.setBannedRoles(collectRolesForPreferenceItem(bannedRoles)) - body.setUseCustomView(false) - body.setUseTabbedView(true) - - body.setView(createLegacyMenuItemViews(filter, caseDefaultHeaders, taskDefaultHeaders)) - - return menuItemService.createMenuItem(body) - } - - /** - * Creates item in menu with given parameters - * - * @param uri resource where the item is located in - * @param identifier unique identifier of item - * @param name displayed label in menu and tab - * @param icon displayed icon in menu and tab - * @param filter Case instance of filter.xml - * @param allowedRoles Map of roles, which have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param bannedRoles Map of roles, which don't have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param caseDefaultHeaders List of headers displayed in case view - * @param taskDefaultHeaders List of headers displayed in task view - * - * @return created Case of menu_item - * */ - @NamedVariant - Case createMenuItem(String uri, String identifier, def name, String icon = "filter_none", Case filter = null, - Map allowedRoles = [:], Map bannedRoles = [:], - List caseDefaultHeaders = [], List taskDefaultHeaders = []) { - MenuItemBody body = new MenuItemBody( - uri, - identifier, - (name instanceof I18nString) ? name : new I18nString(name as String), - icon - ) - - body.setAllowedRoles(collectRolesForPreferenceItem(allowedRoles)) - body.setBannedRoles(collectRolesForPreferenceItem(bannedRoles)) - body.setUseCustomView(false) - body.setUseTabbedView(true) - - body.setView(createLegacyMenuItemViews(filter, caseDefaultHeaders, taskDefaultHeaders)) - - return menuItemService.createMenuItem(body) - } - /** * Changes data of provided menu_item instance. These attributes can be changed: *
    @@ -1899,31 +1557,31 @@ class ActionDelegate { title : { cl -> def value = cl() I18nString newName = (value instanceof I18nString) ? value : new I18nString(value as String) - setData(MenuItemConstants.TRANS_SETTINGS_ID, item, [ + setData(MenuItemConstants.TRANS_SYNC_ID, item, [ (MenuItemConstants.FIELD_MENU_NAME): ["type": "i18n", "value": newName] ]) }, menuIcon : { cl -> def value = cl() - setData(MenuItemConstants.TRANS_SETTINGS_ID, item, [ + setData(MenuItemConstants.TRANS_SYNC_ID, item, [ (MenuItemConstants.FIELD_MENU_ICON): ["type": "text", "value": value] ]) }, tabIcon : { cl -> def value = cl() - setData(MenuItemConstants.TRANS_SETTINGS_ID, item, [ + setData(MenuItemConstants.TRANS_SYNC_ID, item, [ (MenuItemConstants.FIELD_TAB_ICON): ["type": "text", "value": value] ]) }, useCustomView : { cl -> def value = cl() - setData(MenuItemConstants.TRANS_SETTINGS_ID, item, [ + setData(MenuItemConstants.TRANS_SYNC_ID, item, [ (MenuItemConstants.FIELD_USE_CUSTOM_VIEW): ["type": "boolean", "value": value] ]) }, customViewSelector: { cl -> def value = cl() - setData(MenuItemConstants.TRANS_SETTINGS_ID, item, [ + setData(MenuItemConstants.TRANS_SYNC_ID, item, [ (MenuItemConstants.FIELD_CUSTOM_VIEW_SELECTOR): ["type": "text", "value": value] ]) }] @@ -1953,178 +1611,25 @@ class ActionDelegate { } } - /** - * simplifies the process of creating a filter, menu item - * @param uri - * @param identifier - unique identifier of menu item - * @param title - * @param query - * @param icon - * @param type - "Case" or "Task" - * @param allowedNets - * @param groupName - name of group to add menu item to - * @param allowedRoles - * @param bannedRoles - * @param visibility - "private" or "public" - * @return - */ - @Deprecated - Case createFilterInMenu(String uri, String identifier, def title, String query, String type, - List allowedNets, - String groupName, - Map allowedRoles = [:], - Map bannedRoles = [:], - List defaultHeaders = [], - String icon = "", - String visibility = DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE) { - FilterBody filterBody = new FilterBody() - filterBody.setTitle((title instanceof I18nString) ? title : new I18nString(title as String)) - filterBody.setQuery(query) - filterBody.setType(type) - filterBody.setAllowedNets(allowedNets) - filterBody.setIcon(icon) - filterBody.setVisibility(visibility) - Case filter = menuItemService.createFilter(filterBody) - Case menuItem = createMenuItem(uri, identifier, filter, groupName, allowedRoles, bannedRoles, defaultHeaders) - return menuItem - } - - /** - * simplifies the process of creating a filter, menu item - * @param uri - * @param identifier - unique identifier of menu item - * @param title - * @param query - * @param icon - * @param type - "Case" or "Task" - * @param allowedNets - * @param allowedRoles - * @param bannedRoles - * @param visibility - "private" or "public" - * @param orgGroup - group to add item to, if null default group is used - * @return - */ - @Deprecated - Case createFilterInMenu(String uri, String identifier, def title, String query, String type, List allowedNets, - Map allowedRoles = [:], - Map bannedRoles = [:], - List defaultHeaders, - String icon = "", - String visibility = DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE, - Case orgGroup = null) { - FilterBody filterBody = new FilterBody() - filterBody.setTitle((title instanceof I18nString) ? title : new I18nString(title as String)) - filterBody.setQuery(query) - filterBody.setType(type) - filterBody.setAllowedNets(allowedNets) - filterBody.setIcon(icon) - filterBody.setVisibility(visibility) - Case filter = menuItemService.createFilter(filterBody) - Case menuItem = createMenuItem(uri, identifier, filter, allowedRoles, bannedRoles, orgGroup, defaultHeaders) - return menuItem - } - - /** - * Creates filter and menu_item instances with given parameters. - * - * @param uri resource where the item is located in - * @param itemIdentifier unique identifier of item - * @param itemAndFilterName displayed label in menu and tab - * @param filterQuery elastic query for filter - * @param filterType type of filter. Possible values: {@value DefaultFiltersRunner#FILTER_TYPE_CASE} or - * {@value DefaultFiltersRunner#FILTER_TYPE_TASK} - * @param filterVisibility possible values: {@value DefaultFiltersRunner#FILTER_VISIBILITY_PRIVATE} or - * {@value DefaultFiltersRunner#FILTER_VISIBILITY_PUBLIC} - * @param filterAllowedNets List of allowed nets. Element of list is process identifier - * @param itemAndFilterIcon displayed icon in menu and tab - * @param itemAllowedRoles Map of roles, which have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param itemBannedRoles Map of roles, which don't have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param itemCaseDefaultHeaders List of headers displayed in case view - * @param itemTaskDefaultHeaders List of headers displayed in task view - * @param filterMetadata metadata for filter. If no value is provided, then default value is used: {@link #defaultFilterMetadata(String)} - * - * @return created {@link Case} instance of menu_item - * */ - @NamedVariant - Case createFilterInMenu(String uri, String itemIdentifier, def itemAndFilterName, String filterQuery, - String filterType, String filterVisibility, List filterAllowedNets = [], - String itemAndFilterIcon = "filter_none", Map itemAllowedRoles = [:], - Map itemBannedRoles = [:], List itemCaseDefaultHeaders = [], - List itemTaskDefaultHeaders = [], def filterMetadata = null) { - FilterBody filterBody = new FilterBody() - filterBody.setTitle((itemAndFilterName instanceof I18nString) ? itemAndFilterName : new I18nString(itemAndFilterName as String)) - filterBody.setQuery(filterQuery) - filterBody.setType(filterType) - filterBody.setAllowedNets(filterAllowedNets) - filterBody.setIcon(itemAndFilterIcon) - filterBody.setVisibility(filterVisibility) - filterBody.setMetadata(filterMetadata as Map) - Case filter = menuItemService.createFilter(filterBody) - Case menuItem = createMenuItem(uri, itemIdentifier, itemAndFilterName, itemAndFilterIcon, filter, itemAllowedRoles, - itemBannedRoles, itemCaseDefaultHeaders, itemTaskDefaultHeaders) - return menuItem - } - - /** - * Creates filter and menu_item instances with given parameters. - * - * @param body configuration class for menu item creation - * @param filterQuery elastic query for filter - * @param filterType type of filter. Possible values: {@value DefaultFiltersRunner#FILTER_TYPE_CASE} or - * {@value DefaultFiltersRunner#FILTER_TYPE_TASK} - * @param filterVisibility possible values: {@value DefaultFiltersRunner#FILTER_VISIBILITY_PRIVATE} or - * {@value DefaultFiltersRunner#FILTER_VISIBILITY_PUBLIC} - * @param filterAllowedNets List of allowed nets. Element of list is process identifier - * @param filterMetadata metadata for filter. If no value is provided, then default value is used: {@link #defaultFilterMetadata(String)} - * - * @return created {@link Case} instance of menu_item - * */ - Case createFilterInMenu(MenuItemBody body, String filterQuery, String filterType, String filterVisibility, - List filterAllowedNets = [], def filterMetadata = null) { - FilterBody filterBody = new FilterBody() - filterBody.setTitle(body.menuName) - filterBody.setQuery(filterQuery) - filterBody.setType(filterType) - filterBody.setAllowedNets(filterAllowedNets) - filterBody.setIcon(body.menuIcon) - filterBody.setVisibility(filterVisibility) - filterBody.setMetadata(filterMetadata as Map) - - body.setView(createLegacyMenuItemViews(filterBody)) - body.setUseTabbedView(true) - - Case menuItem = createMenuItem(body) - return menuItem - } - Case createMenuItem(MenuItemBody body) { return menuItemService.createMenuItem(body) } - protected ViewBody createLegacyMenuItemViews(Case filterCase, List caseDefaultHeaders = null, - List taskDefaultHeaders = null) { - FilterBody body = new FilterBody(filterCase) - body.setType((String) filterCase?.getFieldValue("filter_type")) - return createLegacyMenuItemViews(body, caseDefaultHeaders, taskDefaultHeaders) - } - protected ViewBody createLegacyMenuItemViews(FilterBody filterBody, List caseDefaultHeaders = null, List taskDefaultHeaders = null) { if (filterBody.getType() == "Case") { - ViewBody caseView = new TabbedCaseViewBody() + ViewBody caseView = new CaseViewBody() caseView.setFilterBody(filterBody) caseView.setDefaultHeaders(caseDefaultHeaders) caseView.setRequireTitleInCreation(true) - ViewBody taskView = new TabbedTaskViewBody() + ViewBody taskView = new TaskViewBody() taskView.setDefaultHeaders(taskDefaultHeaders) caseView.setChainedView(taskView) return caseView } else if (filterBody.getType() == "Task") { - ViewBody taskView = new TabbedTaskViewBody() + ViewBody taskView = new TaskViewBody() taskView.setFilterBody(filterBody) taskView.setDefaultHeaders(taskDefaultHeaders) return taskView @@ -2162,17 +1667,6 @@ class ActionDelegate { return menuItemService.duplicateItem(originItem, newTitle, newIdentifier) } - /** - * Finds filter by name - * - * @param name Title of the filter - * - * @return found filter instance. Can be null - */ - Case findFilter(String name) { - return findCaseElastic("processIdentifier:$FilterRunner.FILTER_PETRI_NET_IDENTIFIER AND title.keyword:\"$name\"" as String) - } - /** * Finds menu item by unique identifier * @@ -2346,158 +1840,10 @@ class ActionDelegate { } as Map } - private void updateFilter(Case filter, Map dataSet) { - setData(DefaultFiltersRunner.DETAILS_TRANSITION, filter, dataSet) - } - I18nString i18n(String value, Map translations) { return new I18nString(value, translations) } - @Deprecated - Map createMenuItem(String id, String uri, String query, String icon, String title, List allowedNets, Map roles, Map bannedRoles = [:], Case group = null, List defaultHeaders = []) { - if (existsMenuItem(id)) { - log.info("$id menu exists") - return null - } - Case filter = createCaseFilter(title, query, allowedNets, icon, DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE) - Case menu = createMenuItem(uri, id, filter, roles, bannedRoles, group, defaultHeaders) - return [ - "filter" : filter, - "menuItem": menu - ] - } - - @Deprecated - Map createTaskMenuItem(String id, String uri, String query, String icon, String title, List allowedNets, Map roles, Case group = null, List defaultHeaders = []) { - if (existsMenuItem(id)) { - log.info("$id menu exists") - return null - } - Case filter = createTaskFilter(title, query, allowedNets, icon, DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE) - Case menu = createMenuItem(uri, id, filter, roles, [:], group, defaultHeaders) - return [ - "filter" : filter, - "menuItem": menu - ] - } - - @Deprecated - Case createOrUpdateCaseMenuItem(String id, String uri, String query, String icon, String title, List allowedNets, Map roles = [:], Map bannedRoles = [:], Case group = null, List defaultHeaders = []) { - return createOrUpdateMenuItemAndFilter(uri, id, title, query, DefaultFiltersRunner.FILTER_TYPE_CASE, - DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE, allowedNets, icon, roles, bannedRoles, defaultHeaders) - } - - @Deprecated - Case createOrUpdateTaskMenuItem(String id, String uri, String query, String icon, String title, List allowedNets, Map roles = [:], Map bannedRoles = [:], Case group = null, List defaultHeaders = []) { - return createOrUpdateMenuItemAndFilter(uri, id, title, query, DefaultFiltersRunner.FILTER_TYPE_TASK, - DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE, allowedNets, icon, roles, bannedRoles, defaultHeaders) - } - - @Deprecated - Case createOrUpdateMenuItem(String id, String uri, String type, String query, String icon, String title, List allowedNets, - Map roles = [:], Map bannedRoles = [:], Case group = null, - List defaultHeaders = []) { - MenuItemBody body = new MenuItemBody(uri, id, title, icon) - body.setAllowedRoles(collectRolesForPreferenceItem(roles)) - body.setBannedRoles(collectRolesForPreferenceItem(bannedRoles)) - body.setUseTabbedView(true) - - FilterBody filterBody = new FilterBody() - filterBody.setTitle(new I18nString(title as String)) - filterBody.setQuery(query) - filterBody.setType(type) - filterBody.setAllowedNets(allowedNets) - filterBody.setIcon(icon) - filterBody.setVisibility(DefaultFiltersRunner.FILTER_VISIBILITY_PRIVATE) - - body.setView(createLegacyMenuItemViews(filterBody, defaultHeaders)) - return menuItemService.createOrUpdateMenuItem(body) - } - - /** - * Creates or updates menu item with given identifier. - * - * @param uri resource where the item is located in - * @param identifier unique identifier of item - * @param name displayed label in menu and tab - * @param icon displayed icon in menu and tab - * @param filter Case instance of filter.xml - * @param allowedRoles Map of roles, which have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param bannedRoles Map of roles, which don't have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param caseDefaultHeaders List of headers displayed in case view - * @param taskDefaultHeaders List of headers displayed in task view - * - * @return created or updated menu item instance - * */ - @Deprecated(since = "6.5.0") - Case createOrUpdateMenuItem(String uri, String identifier, def name, String icon = "filter_none", Case filter = null, - Map allowedRoles = [:], Map bannedRoles = [:], - List caseDefaultHeaders = [], List taskDefaultHeaders = []) { - MenuItemBody body = new MenuItemBody(uri, identifier, name, icon) - body.setAllowedRoles(collectRolesForPreferenceItem(allowedRoles)) - body.setBannedRoles(collectRolesForPreferenceItem(bannedRoles)) - body.setUseTabbedView(true) - if (filter == null) { - body.setView(createLegacyMenuItemViews(new FilterBody(null), caseDefaultHeaders, taskDefaultHeaders)) - } else { - body.setView(createLegacyMenuItemViews(filter, caseDefaultHeaders, taskDefaultHeaders)) - } - - return createOrUpdateMenuItem(body) - } - - /** - * Creates or updates menu item with given identifier along with the filter instance. It's safe to use on existing - * menu item instance, that doesn't contain filter. In such case, missing filter will be created with provided - * parameters. - * - * @param uri resource where the item is located in - * @param itemIdentifier unique identifier of item - * @param itemAndFilterName displayed label in menu and tab - * @param filterQuery elastic query for filter - * @param filterType type of filter. Possible values: {@value DefaultFiltersRunner#FILTER_TYPE_CASE} or - * {@value DefaultFiltersRunner#FILTER_TYPE_TASK} - * @param filterVisibility possible values: {@value DefaultFiltersRunner#FILTER_VISIBILITY_PRIVATE} or - * {@value DefaultFiltersRunner#FILTER_VISIBILITY_PUBLIC} - * @param filterAllowedNets List of allowed nets. Element of list is process identifier - * @param itemAndFilterIcon displayed icon in menu and tab - * @param itemAllowedRoles Map of roles, which have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param itemBannedRoles Map of roles, which don't have access to the item. Key is role_id in XML and value is process - * identifier where the role exists - * @param itemCaseDefaultHeaders List of headers displayed in case view - * @param itemTaskDefaultHeaders List of headers displayed in task view - * @param filterMetadata metadata for filter. If no value is provided, then default value is used: {@link #defaultFilterMetadata(String)} - * - * @return created or updated menu item instance along with the actual filter - * */ - @Deprecated(since = "6.5.0") - Case createOrUpdateMenuItemAndFilter(String uri, String itemIdentifier, def itemAndFilterName, String filterQuery, - String filterType, String filterVisibility, List filterAllowedNets = [], - String itemAndFilterIcon = "filter_none", Map itemAllowedRoles = [:], - Map itemBannedRoles = [:], List itemCaseDefaultHeaders = [], - List itemTaskDefaultHeaders = [], def filterMetadata = null) { - MenuItemBody body = new MenuItemBody(uri, itemIdentifier, itemAndFilterName, itemAndFilterIcon) - body.allowedRoles = collectRolesForPreferenceItem(itemAllowedRoles) - body.bannedRoles = collectRolesForPreferenceItem(itemBannedRoles) - body.setUseTabbedView(true) - - FilterBody filterBody = new FilterBody() - filterBody.setTitle((itemAndFilterName instanceof I18nString) ? itemAndFilterName : new I18nString(itemAndFilterName as String)) - filterBody.setQuery(filterQuery) - filterBody.setType(filterType) - filterBody.setAllowedNets(filterAllowedNets) - filterBody.setIcon(itemAndFilterIcon) - filterBody.setVisibility(filterVisibility) - filterBody.setMetadata(filterMetadata as Map) - body.setView(createLegacyMenuItemViews(filterBody, itemCaseDefaultHeaders, itemTaskDefaultHeaders)) - - return menuItemService.createOrUpdateMenuItem(body) - } - /** * Creates or updates menu item with given identifier. * @@ -2509,40 +1855,6 @@ class ActionDelegate { return menuItemService.createOrUpdateMenuItem(body) } - /** - * Creates or updates menu item with given identifier along with the filter instance. It's safe to use on existing - * menu item instance, that doesn't contain filter. In such case, missing filter will be created with provided - * parameters. - * - * @param body data for menu item - * @param filterQuery elastic query for filter - * @param filterType type of filter. Possible values: {@value DefaultFiltersRunner#FILTER_TYPE_CASE} or - * {@value DefaultFiltersRunner#FILTER_TYPE_TASK} - * @param filterVisibility possible values: {@value DefaultFiltersRunner#FILTER_VISIBILITY_PRIVATE} or - * {@value DefaultFiltersRunner#FILTER_VISIBILITY_PUBLIC} - * @param filterAllowedNets List of allowed nets. Element of list is process identifier - * @param filterMetadata metadata for filter. If no value is provided, then default value is used: {@link #defaultFilterMetadata(String)} - * - * @return created or updated menu item instance along with the actual filter - * */ - @Deprecated(since = "6.5.0") - Case createOrUpdateMenuItemAndFilter(MenuItemBody body, String filterQuery, String filterType, String filterVisibility, - List filterAllowedNets = [], def filterMetadata = null) { - body.setUseTabbedView(true) - - FilterBody filterBody = new FilterBody() - filterBody.setTitle(body.getMenuName()) - filterBody.setQuery(filterQuery) - filterBody.setType(filterType) - filterBody.setAllowedNets(filterAllowedNets) - filterBody.setIcon(body.getMenuIcon()) - filterBody.setVisibility(filterVisibility) - filterBody.setMetadata(filterMetadata as Map) - body.setView(createLegacyMenuItemViews(filterBody)) - - return menuItemService.createOrUpdateMenuItem(body) - } - /** * Creates menu item or ignores it if already exists * @@ -2554,33 +1866,6 @@ class ActionDelegate { return menuItemService.createOrIgnoreMenuItem(body) } - /** - * Creates menu item or ignores it if already exists. If existing item does not contain filter, the filter instance - * is created by provided parameters. - * - * @param body configuration class for menu item - * - * @return created or existing menu item instance - * */ - @Deprecated(since = "6.5.0") - Case createOrIgnoreMenuItemAndFilter(MenuItemBody body, String filterQuery, String filterType, String filterVisibility, - List filterAllowedNets = [], def filterMetadata = null) { - body.setUseTabbedView(true) - - FilterBody filterBody = new FilterBody() - filterBody.setTitle(body.getMenuName()) - filterBody.setQuery(filterQuery) - filterBody.setType(filterType) - filterBody.setAllowedNets(filterAllowedNets) - filterBody.setIcon(body.getMenuIcon()) - filterBody.setVisibility(filterVisibility) - filterBody.setMetadata(filterMetadata as Map) - - body.setView(createLegacyMenuItemViews(filterBody)) - - return menuItemService.createOrIgnoreMenuItem(body) - } - /** * Updates existing menu item with provided values. * @@ -2593,10 +1878,6 @@ class ActionDelegate { return menuItemService.updateMenuItem(item, body) } - static Map defaultFilterMetadata(String type) { - return FilterBody.getDefaultMetadata(type) - } - void removeChildItemFromParent(String folderId, Case childItem) { menuItemService.removeChildItemFromParent(folderId, childItem) } diff --git a/src/main/groovy/com/netgrif/application/engine/startup/DefaultDashboardRunner.groovy b/src/main/groovy/com/netgrif/application/engine/startup/DefaultDashboardRunner.groovy index 7e5475ef098..1e580755668 100644 --- a/src/main/groovy/com/netgrif/application/engine/startup/DefaultDashboardRunner.groovy +++ b/src/main/groovy/com/netgrif/application/engine/startup/DefaultDashboardRunner.groovy @@ -2,7 +2,7 @@ package com.netgrif.application.engine.startup import com.netgrif.application.engine.menu.domain.dashboard.DashboardManagementBody -import com.netgrif.application.engine.menu.services.interfaces.DashboardManagementService +import com.netgrif.application.engine.menu.service.interfaces.DashboardManagementService import com.netgrif.application.engine.petrinet.domain.I18nString import org.springframework.beans.factory.annotation.Autowired import org.springframework.stereotype.Component diff --git a/src/main/groovy/com/netgrif/application/engine/startup/DefaultFiltersRunner.groovy b/src/main/groovy/com/netgrif/application/engine/startup/DefaultFiltersRunner.groovy deleted file mode 100644 index 3f2f1e2b371..00000000000 --- a/src/main/groovy/com/netgrif/application/engine/startup/DefaultFiltersRunner.groovy +++ /dev/null @@ -1,314 +0,0 @@ -package com.netgrif.application.engine.startup - -import com.netgrif.application.engine.auth.service.interfaces.IUserService -import com.netgrif.application.engine.petrinet.domain.I18nString -import com.netgrif.application.engine.petrinet.domain.PetriNet -import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService -import com.netgrif.application.engine.workflow.domain.Case -import com.netgrif.application.engine.workflow.domain.QCase -import com.netgrif.application.engine.workflow.domain.QTask -import com.netgrif.application.engine.workflow.domain.Task -import com.netgrif.application.engine.workflow.service.interfaces.IDataService -import com.netgrif.application.engine.workflow.service.interfaces.ITaskService -import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService -import lombok.extern.slf4j.Slf4j -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Component -import org.springframework.beans.factory.annotation.Value - -@Slf4j -@Component -class DefaultFiltersRunner extends AbstractOrderedCommandLineRunner { - - public static final String AUTO_CREATE_TRANSITION = "auto_create" - public static final String DETAILS_TRANSITION = "t2" - - public static final String FILTER_TYPE_FIELD_ID = "filter_type" - public static final String FILTER_ORIGIN_VIEW_ID_FIELD_ID = "origin_view_id" - public static final String FILTER_PARENT_CASE_ID_FIELD_ID = "parent_filter_id" - public static final String FILTER_VISIBILITY_FIELD_ID = "visibility" - public static final String FILTER_FIELD_ID = "filter" - public static final String FILTER_I18N_TITLE_FIELD_ID = "i18n_filter_name" - public static final String GERMAN_ISO_3166_CODE = "de" - public static final String SLOVAK_ISO_3166_CODE = "sk" - public static final String IS_IMPORTED = "is_imported" - - public static final String FILTER_TYPE_CASE = "Case" - public static final String FILTER_TYPE_TASK = "Task" - - public static final String FILTER_VISIBILITY_PRIVATE = "private" - public static final String FILTER_VISIBILITY_PUBLIC = "public" - - @Value('${nae.create.default.filters:false}') - private Boolean createDefaultFilters - - @Autowired - private IPetriNetService petriNetService - - @Autowired - private IWorkflowService workflowService - - @Autowired - private IUserService userService - - @Autowired - private ITaskService taskService - - @Autowired - private IDataService dataService - - @Override - void run(String... args) throws Exception { - if (createDefaultFilters) { - createCaseFilter("All cases", "assignment", FILTER_VISIBILITY_PUBLIC, "", [], [ - "predicateMetadata": [], - "searchCategories" : [] - ], [ - (GERMAN_ISO_3166_CODE): "Alle Fälle", - (SLOVAK_ISO_3166_CODE): "Všetky prípady" - ]) - createCaseFilter("My cases", "assignment_ind", FILTER_VISIBILITY_PUBLIC, "(author:<>)", [], [ - "predicateMetadata": [[["category": "case_author", "configuration": ["operator": "equals"], "values": [["text": "search.category.userMe", value: ["<>"]]]]]], - "searchCategories" : ["case_author"] - ], [ - (GERMAN_ISO_3166_CODE): "Meine Fälle", - (SLOVAK_ISO_3166_CODE): "Moje prípady" - ]) - - createTaskFilter("All tasks", "library_add_check", FILTER_VISIBILITY_PUBLIC, "", [], [ - "predicateMetadata": [], - "searchCategories" : [] - ], [ - (GERMAN_ISO_3166_CODE): "Alle Aufgaben", - (SLOVAK_ISO_3166_CODE): "Všetky úlohy" - ]) - createTaskFilter("My tasks", "account_box", FILTER_VISIBILITY_PUBLIC, "(userId:<>)", [], [ - "predicateMetadata": [[["category": "task_assignee", "configuration": ["operator": "equals"], "values": [["text": "search.category.userMe", value: ["<>"]]]]]], - "searchCategories" : ["task_assignee"] - ], [ - (GERMAN_ISO_3166_CODE): "Meine Aufgaben", - (SLOVAK_ISO_3166_CODE): "Moje úlohy" - ]) - } - } - - /** - * Creates a new case filter filter process instance - * @param title unique title of the default filter - * @param icon material icon identifier of the default filter - * @param filterVisibility filter visibility - * @param filterQuery the elastic query string query used by the filter - * @param allowedNets list of process identifiers allowed for search categories metadata generation - * @param filterMetadata metadata of the serialised filter as generated by the frontend - * @param titleTranslations a map of locale codes to translated strings for the filter title - * @param withDefaultCategories whether the default search categories should be merged with the search categories specified in the metadata - * @param inheritBaseAllowedNets whether the base allowed nets should be merged with the allowed nets specified in the filter field - * @param originId the ID of the parent if any - * @param viewOrigin true if the parent was a view. false if the parent was another filter - * @param isImported whether the filter is being created by importing it from na XML file - * @return an empty Optional if the filter process does not exist. An existing filter process instance if a filter process instance with the same name already exists. A new filter process instance if not. - */ - Optional createCaseFilter( - String title, - String icon, - String filterVisibility, - String filterQuery, - List allowedNets, - Map filterMetadata, - Map titleTranslations, - boolean withDefaultCategories = true, - boolean inheritBaseAllowedNets = true, - String originId = null, - boolean viewOrigin = false, - boolean isImported = false - ) { - return createFilter( - title, - icon, - FILTER_TYPE_CASE, - filterVisibility, - filterQuery, - allowedNets, - filterMetadata, - titleTranslations, - withDefaultCategories, - inheritBaseAllowedNets, - originId, - viewOrigin, - isImported - ) - } - - /** - * Creates a new task filter filter process instance - * @param title unique title of the default filter - * @param icon material icon identifier of the default filter - * @param filterVisibility filter visibility - * @param filterQuery the elastic query string query used by the filter - * @param allowedNets list of process identifiers allowed for search categories metadata generation - * @param filterMetadata metadata of the serialised filter as generated by the frontend - * @param titleTranslations a map of locale codes to translated strings for the filter title - * @param withDefaultCategories whether the default search categories should be merged with the search categories specified in the metadata - * @param inheritBaseAllowedNets whether the base allowed nets should be merged with the allowed nets specified in the filter field - * @param originId the ID of the parent if any - * @param viewOrigin true if the parent was a view. false if the parent was another filter - * @param isImported whether the filter is being created by importing it from na XML file - * @return an empty Optional if the filter process does not exist. An existing filter process instance if a filter process instance with the same name already exists. A new filter process instance if not. - */ - Optional createTaskFilter( - String title, - String icon, - String filterVisibility, - String filterQuery, - List allowedNets, - Map filterMetadata, - Map titleTranslations, - boolean withDefaultCategories = true, - boolean inheritBaseAllowedNets = true, - String originId = null, - boolean viewOrigin = false, - boolean isImported = false - ) { - return createFilter( - title, - icon, - FILTER_TYPE_TASK, - filterVisibility, - filterQuery, - allowedNets, - filterMetadata, - titleTranslations, - withDefaultCategories, - inheritBaseAllowedNets, - originId, - viewOrigin, - isImported - ) - } - - /** - * Creates a new filter process instance of the provided type - * @param title unique title of the default filter - * @param icon material icon identifier of the default filter - * @param filterType the type of the filter - * @param filterVisibility filter visibility - * @param filterQuery the elastic query string query used by the filter - * @param allowedNets list of process identifiers allowed for search categories metadata generation - * @param filterMetadata metadata of the serialised filter as generated by the frontend - * @param titleTranslations a map of locale codes to translated strings for the filter title - * @param withDefaultCategories whether the default search categories should be merged with the search categories specified in the metadata - * @param inheritBaseAllowedNets whether the base allowed nets should be merged with the allowed nets specified in the filter field - * @param originId the ID of the parent if any - * @param viewOrigin true if the parent was a view. false if the parent was another filter - * @param isImported whether the filter is being created by importing it from na XML file - * @return an empty Optional if the filter process does not exist. An existing filter process instance if a filter process instance with the same name already exists. A new filter process instance if not. - */ - Optional createFilter( - String title, - String icon, - String filterType, - String filterVisibility, - String filterQuery, - List allowedNets, - Map filterMetadata, - Map titleTranslations, - boolean withDefaultCategories, - boolean inheritBaseAllowedNets, - String originId = null, - boolean viewOrigin = false, - boolean isImported = false - ) { - return createFilterCase( - title, - icon, - filterType, - filterVisibility, - filterQuery, - allowedNets, - filterMetadata << ["filterType": filterType, "defaultSearchCategories": withDefaultCategories, "inheritAllowedNets": inheritBaseAllowedNets], - titleTranslations, - originId, - viewOrigin, - isImported - ) - } - - private Optional createFilterCase( - String title, - String icon, - String filterType, - String filterVisibility, - String filterQuery, - List allowedNets, - Map filterMetadata, - Map titleTranslations, - String originId, - boolean viewOrigin, - boolean isImported - ) { - PetriNet filterNet = this.petriNetService.getNewestVersionByIdentifier('filter') - if (filterNet == null) { - return Optional.empty() - } - - def loggedUser = this.userService.getLoggedOrSystem() - - if (loggedUser.getStringId() == this.userService.getSystem().getStringId()) { - Case filterCase = this.workflowService.searchOne(QCase.case$.processIdentifier.eq("filter").and(QCase.case$.title.eq(title)).and(QCase.case$.author.id.eq(userService.getSystem().getStringId()))) - if (filterCase != null) { - return Optional.of(filterCase) - } - } - - Case filterCase = this.workflowService.createCase(filterNet.getStringId(), title, null, loggedUser.transformToLoggedUser()).getCase() - filterCase.setIcon(icon) - filterCase = this.workflowService.save(filterCase) - Task newFilterTask = this.taskService.searchOne(QTask.task.transitionId.eq(AUTO_CREATE_TRANSITION).and(QTask.task.caseId.eq(filterCase.getStringId()))) - this.taskService.assignTask(newFilterTask, this.userService.getLoggedOrSystem()) - - def setDataMap = [ - (FILTER_TYPE_FIELD_ID): [ - "type": "enumeration_map", - "value": filterType - ], - (FILTER_VISIBILITY_FIELD_ID): [ - "type": "enumeration_map", - "value": filterVisibility - ], - (FILTER_FIELD_ID): [ - "type": "filter", - "value": filterQuery, - "allowedNets": allowedNets, - "filterMetadata": filterMetadata - ] - ] - - if (originId != null) { - setDataMap.put(viewOrigin ? FILTER_ORIGIN_VIEW_ID_FIELD_ID : FILTER_PARENT_CASE_ID_FIELD_ID, [ - "type": "text", - "value": originId - ]) - } - - - this.dataService.setData(newFilterTask, ImportHelper.populateDataset(setDataMap)) - if (isImported) { - this.dataService.setData(newFilterTask, ImportHelper.populateDataset([ - (IS_IMPORTED): [ - "type": "number", - "value": 1 - ] - ])) - } - - I18nString translatedTitle = new I18nString(title) - titleTranslations.forEach({locale, translation -> translatedTitle.addTranslation(locale, translation)}) - - filterCase = this.workflowService.findOne(filterCase.getStringId()) - filterCase.dataSet[FILTER_I18N_TITLE_FIELD_ID].value = translatedTitle - workflowService.save(filterCase) - - this.taskService.finishTask(newFilterTask, this.userService.getLoggedOrSystem()) - return Optional.of(this.workflowService.findOne(filterCase.getStringId())) - } -} diff --git a/src/main/groovy/com/netgrif/application/engine/startup/FilterRunner.groovy b/src/main/groovy/com/netgrif/application/engine/startup/FilterRunner.groovy deleted file mode 100644 index fe45689889b..00000000000 --- a/src/main/groovy/com/netgrif/application/engine/startup/FilterRunner.groovy +++ /dev/null @@ -1,59 +0,0 @@ -package com.netgrif.application.engine.startup - -import com.netgrif.application.engine.menu.domain.MenuItemView -import com.netgrif.application.engine.petrinet.domain.PetriNet -import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService -import groovy.util.logging.Slf4j -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.stereotype.Component - -@Slf4j -@Component -class FilterRunner extends AbstractOrderedCommandLineRunner { - - @Autowired - private ImportHelper helper - - @Autowired - private IPetriNetService petriNetService - - @Autowired - private SystemUserRunner systemCreator - - private static final String FILTER_FILE_NAME = "engine-processes/filter.xml" - public static final String FILTER_PETRI_NET_IDENTIFIER = "filter" - - private static final String MENU_ITEM_FILE_NAME = "engine-processes/menu/menu_item.xml" - public static final String MENU_NET_IDENTIFIER = "menu_item" - - private static final String EXPORT_FILTER_FILE_NAME = "engine-processes/export_filters.xml" - private static final String EXPORT_NET_IDENTIFIER = "export_filters" - - private static final String IMPORT_FILTER_FILE_NAME = "engine-processes/import_filters.xml" - private static final String IMPORT_NET_IDENTIFIER = "import_filters" - - @Override - void run(String... args) throws Exception { - helper.importProcess("Petri net for filters", FILTER_PETRI_NET_IDENTIFIER, FILTER_FILE_NAME) - createConfigurationNets() - helper.importProcess("Petri net for filter preferences", MENU_NET_IDENTIFIER, MENU_ITEM_FILE_NAME) - createImportFiltersNet() - createExportFiltersNet() - } - - Optional createImportFiltersNet() { - helper.importProcess("Petri net for importing filters", IMPORT_NET_IDENTIFIER, IMPORT_FILTER_FILE_NAME) - } - - Optional createExportFiltersNet() { - helper.importProcess("Petri net for exporting filters", EXPORT_NET_IDENTIFIER, EXPORT_FILTER_FILE_NAME) - } - - private List createConfigurationNets() { - return MenuItemView.values().each { view -> - String processIdentifier = view.getIdentifier() + "_configuration" - String filePath = String.format("engine-processes/menu/%s.xml", processIdentifier) - helper.importProcess(String.format("Petri net for %s", processIdentifier), processIdentifier, filePath) - }.collect() - } -} diff --git a/src/main/groovy/com/netgrif/application/engine/startup/MenuRunner.groovy b/src/main/groovy/com/netgrif/application/engine/startup/MenuRunner.groovy new file mode 100644 index 00000000000..472d9bb5a79 --- /dev/null +++ b/src/main/groovy/com/netgrif/application/engine/startup/MenuRunner.groovy @@ -0,0 +1,39 @@ +package com.netgrif.application.engine.startup + +import com.netgrif.application.engine.menu.domain.MenuItemConstants +import com.netgrif.application.engine.menu.domain.MenuItemViewType +import com.netgrif.application.engine.petrinet.domain.PetriNet +import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService +import groovy.util.logging.Slf4j +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component + +@Slf4j +@Component +class MenuRunner extends AbstractOrderedCommandLineRunner { + + private static final String MENU_ITEM_FILE_NAME = "engine-processes/menu/menu_item.xml" + + @Autowired + private ImportHelper helper + + @Autowired + private IPetriNetService petriNetService + + @Autowired + private SystemUserRunner systemCreator + + @Override + void run(String... args) throws Exception { + createConfigurationNets() + helper.importProcess("Petri net for menu item", MenuItemConstants.PROCESS_IDENTIFIER, MENU_ITEM_FILE_NAME) + } + + private void createConfigurationNets() { + MenuItemViewType.values().each { view -> + String processIdentifier = view.getIdentifier() + "_configuration" + String filePath = String.format("engine-processes/menu/%s.xml", processIdentifier) + helper.importProcess(String.format("Petri net for %s", processIdentifier), processIdentifier, filePath) + }.collect() + } +} diff --git a/src/main/groovy/com/netgrif/application/engine/startup/MongoDbRunner.groovy b/src/main/groovy/com/netgrif/application/engine/startup/MongoDbRunner.groovy index 4fac0dc985e..670b97b214a 100644 --- a/src/main/groovy/com/netgrif/application/engine/startup/MongoDbRunner.groovy +++ b/src/main/groovy/com/netgrif/application/engine/startup/MongoDbRunner.groovy @@ -1,10 +1,11 @@ package com.netgrif.application.engine.startup + +import com.netgrif.application.engine.menu.service.interfaces.IMenuItemService import org.slf4j.Logger import org.slf4j.LoggerFactory import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Profile import org.springframework.data.mapping.context.MappingContext import org.springframework.data.mongodb.core.MongoTemplate import org.springframework.data.mongodb.core.index.IndexOperations @@ -16,7 +17,6 @@ import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty import org.springframework.stereotype.Component @Component -@Profile("!test") class MongoDbRunner extends AbstractOrderedCommandLineRunner { private static final Logger log = LoggerFactory.getLogger(MongoDbRunner) @@ -24,6 +24,9 @@ class MongoDbRunner extends AbstractOrderedCommandLineRunner { @Autowired private MongoTemplate mongoTemplate + @Autowired + private IMenuItemService menuItemService + @Value('${spring.data.mongodb.database}') private String name @@ -48,23 +51,25 @@ class MongoDbRunner extends AbstractOrderedCommandLineRunner { if (host != null && port != null) log.info("Dropping Mongo database ${host}:${port}/${name}") else if (uri != null) - log.info("Droppiung Mongo database ${uri}") + log.info("Dropping Mongo database ${uri}") mongoTemplate.getDb().drop() } if (resolveIndexesOnStartup) { + log.info("Ensuring Mongo indexes") resolveIndexes() } } - void resolveIndexes() { + private void resolveIndexes() { MappingContext, MongoPersistentProperty> mappingContext = mongoTemplate.getConverter().getMappingContext() IndexResolver resolver = new MongoPersistentEntityIndexResolver(mappingContext) mappingContext.getPersistentEntities() .stream() .filter(it -> it.isAnnotationPresent(Document.class)) .forEach(it -> { - IndexOperations indexOps = mongoTemplate.indexOps(it.getType()); - resolver.resolveIndexFor(it.getType()).forEach(indexOps::ensureIndex); + IndexOperations indexOps = mongoTemplate.indexOps(it.getType()) + resolver.resolveIndexFor(it.getType()).forEach(indexOps::ensureIndex) }) + menuItemService.ensureDatabaseIndexes() } } \ No newline at end of file diff --git a/src/main/groovy/com/netgrif/application/engine/startup/RunnerController.groovy b/src/main/groovy/com/netgrif/application/engine/startup/RunnerController.groovy index 14c9c83b234..fd7444cc20b 100644 --- a/src/main/groovy/com/netgrif/application/engine/startup/RunnerController.groovy +++ b/src/main/groovy/com/netgrif/application/engine/startup/RunnerController.groovy @@ -16,9 +16,8 @@ class RunnerController { SystemUserRunner, UriRunner, FunctionsCacheRunner, - FilterRunner, + MenuRunner, GroupRunner, - DefaultFiltersRunner, ImpersonationRunner, DashboardRunner, DashboardManagementRunner, diff --git a/src/main/java/com/netgrif/application/engine/auth/service/UserService.java b/src/main/java/com/netgrif/application/engine/auth/service/UserService.java index b31836c11b9..cf74d3c5d43 100755 --- a/src/main/java/com/netgrif/application/engine/auth/service/UserService.java +++ b/src/main/java/com/netgrif/application/engine/auth/service/UserService.java @@ -10,7 +10,6 @@ import com.netgrif.application.engine.orgstructure.groups.interfaces.INextGroupService; import com.netgrif.application.engine.petrinet.service.interfaces.IProcessRoleService; import com.netgrif.application.engine.startup.SystemUserRunner; -import com.netgrif.application.engine.workflow.service.interfaces.IFilterImportExportService; import com.querydsl.core.types.dsl.BooleanExpression; import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; @@ -50,9 +49,6 @@ public class UserService extends AbstractUserService { @Autowired private GroupConfigurationProperties groupProperties; - @Autowired - private IFilterImportExportService filterImportExportService; - @Override public IUser saveNewAndAuthenticate(IUser user) { return saveNew(user, true); @@ -70,8 +66,6 @@ private IUser saveNew(IUser user, boolean login) { addDefaultAuthorities(user); User savedUser = userRepository.save((User) user); - filterImportExportService.createFilterImport(user); - filterImportExportService.createFilterExport(user); if (groupProperties.isDefaultEnabled()) groupService.createGroup(user); diff --git a/src/main/java/com/netgrif/application/engine/importer/service/FieldFactory.java b/src/main/java/com/netgrif/application/engine/importer/service/FieldFactory.java index 4ac4a03c32c..850e4dbe0be 100644 --- a/src/main/java/com/netgrif/application/engine/importer/service/FieldFactory.java +++ b/src/main/java/com/netgrif/application/engine/importer/service/FieldFactory.java @@ -197,8 +197,8 @@ public static String parseEnumerationMapValue(Case useCase, String fieldId) { } // TODO: refactor this shit - Field getField(Data data, Importer importer) throws IllegalArgumentException, MissingIconKeyException { - Field field; + Field getField(Data data, Importer importer) throws IllegalArgumentException, MissingIconKeyException { + Field field; switch (data.getType()) { case TEXT: field = buildTextField(data); @@ -248,8 +248,15 @@ Field getField(Data data, Importer importer) throws IllegalArgumentException, Mi case MULTICHOICE_MAP: field = buildMultichoiceMapField(data, importer); break; - case FILTER: - field = buildFilterField(data); + case FILTER: // "FILTER" is deprecated + case CASE_FILTER: + field = buildCaseFilterField(data); + break; + case TASK_FILTER: + field = buildTaskFilterField(data); + break; + case PROCESS_FILTER: + field = buildProcessFilterField(data); break; case I_18_N: field = buildI18nField(data, importer); @@ -549,13 +556,22 @@ private FileListField buildFileListField(Data data) { return fileListField; } - private FilterField buildFilterField(Data data) { - AllowedNets nets = data.getAllowedNets(); - if (nets == null) { - return new FilterField(); - } else { - return new FilterField(new ArrayList<>(nets.getAllowedNet())); - } + private CaseFilterField buildCaseFilterField(Data data) { + CaseFilterField field = new CaseFilterField(); + setDefaultValue(field, data, field::setDefaultValue); + return field; + } + + private TaskFilterField buildTaskFilterField(Data data) { + TaskFilterField field = new TaskFilterField(); + setDefaultValue(field, data, field::setDefaultValue); + return field; + } + + private ProcessFilterField buildProcessFilterField(Data data) { + ProcessFilterField field = new ProcessFilterField(); + setDefaultValue(field, data, field::setDefaultValue); + return field; } private I18nField buildI18nField(Data data, Importer importer) { @@ -611,8 +627,6 @@ private Field buildField(Case useCase, String fieldId, boolean withValidation, S resolveMapOptions((MapOptionsField) field, useCase); if (field instanceof FieldWithAllowedNets) resolveAllowedNets((FieldWithAllowedNets) field, useCase); - if (field instanceof FilterField) - resolveFilterMetadata((FilterField) field, useCase); if (withValidation) resolveValidations(field, useCase); return field; @@ -661,13 +675,6 @@ private void resolveAllowedNets(FieldWithAllowedNets field, Case useCase) { field.setAllowedNets(allowedNets); } - private void resolveFilterMetadata(FilterField field, Case useCase) { - Map metadata = useCase.getDataField(field.getImportId()).getFilterMetadata(); - if (metadata == null) - return; - field.setFilterMetadata(metadata); - } - public Field buildImmediateField(Case useCase, String fieldId) { Field field = useCase.getPetriNet().getDataSet().get(fieldId).clone(); resolveDataValues(field, useCase, fieldId); @@ -788,14 +795,10 @@ private void parseFileListValue(FileListField field, Case useCase, String fieldI private void resolveAttributeValues(Field field, Case useCase, String fieldId) { DataField dataField = useCase.getDataSet().get(fieldId); - if (field.getType().equals(FieldType.CASE_REF) || field.getType().equals(FieldType.FILTER)) { + if (field.getType().equals(FieldType.CASE_REF)) { List allowedNets = new ArrayList<>(dataField.getAllowedNets()); ((FieldWithAllowedNets) field).setAllowedNets(allowedNets); } - if (field.getType().equals(FieldType.FILTER)) { - Map filterMetadata = new HashMap<>(dataField.getFilterMetadata()); - ((FilterField) field).setFilterMetadata(filterMetadata); - } } private void setDefaultValue(Field field, Data data, Consumer setDefault) { diff --git a/src/main/java/com/netgrif/application/engine/importer/service/Importer.java b/src/main/java/com/netgrif/application/engine/importer/service/Importer.java index 596db2e301f..c333a31bf9c 100644 --- a/src/main/java/com/netgrif/application/engine/importer/service/Importer.java +++ b/src/main/java/com/netgrif/application/engine/importer/service/Importer.java @@ -39,7 +39,6 @@ import lombok.extern.slf4j.Slf4j; import org.bson.types.ObjectId; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; @@ -123,7 +122,6 @@ public class Importer { @Autowired private ILogicValidator logicValidator; - @Transactional public Optional importPetriNet(InputStream xml) throws MissingPetriNetMetaDataException, MissingIconKeyException { try { initialize(); @@ -135,7 +133,6 @@ public Optional importPetriNet(InputStream xml) throws MissingPetriNet return Optional.empty(); } - @Transactional public Optional importPetriNet(File xml) throws MissingPetriNetMetaDataException, MissingIconKeyException { try { return importPetriNet(new FileInputStream(xml)); @@ -159,7 +156,6 @@ protected void initialize() { this.functions = new LinkedList<>(); } - @Transactional protected void unmarshallXml(InputStream xml) throws JAXBException { JAXBContext jaxbContext = JAXBContext.newInstance(Document.class); @@ -167,7 +163,6 @@ protected void unmarshallXml(InputStream xml) throws JAXBException { document = (Document) jaxbUnmarshaller.unmarshal(xml); } - @Transactional public Path saveNetFile(PetriNet net, InputStream xmlFile) throws IOException { File savedFile = new File(fileStorageConfiguration.getStorageArchived() + net.getStringId() + "-" + net.getTitle() + FILE_EXTENSION); savedFile.getParentFile().mkdirs(); @@ -176,7 +171,6 @@ public Path saveNetFile(PetriNet net, InputStream xmlFile) throws IOException { return savedFile.toPath(); } - @Transactional protected Optional createPetriNet() throws MissingPetriNetMetaDataException, MissingIconKeyException { net = new PetriNet(); @@ -225,7 +219,6 @@ protected Optional createPetriNet() throws MissingPetriNetMetaDataExce return Optional.of(net); } - @Transactional protected void resolveRoleRef(CaseRoleRef roleRef) { CaseLogic logic = roleRef.getCaseLogic(); String roleId = getRole(roleRef.getId()).getStringId(); @@ -240,7 +233,6 @@ protected void resolveRoleRef(CaseRoleRef roleRef) { net.addPermission(roleId, roleFactory.getProcessPermissions(logic)); } - @Transactional protected void createFunction(com.netgrif.application.engine.importer.model.Function function) { com.netgrif.application.engine.petrinet.domain.Function fun = functionFactory.getFunction(function); @@ -248,8 +240,7 @@ protected void createFunction(com.netgrif.application.engine.importer.model.Func functions.add(fun); } - @Transactional - protected void resolveUserRef(CaseUserRef userRef) { + protected void resolveUserRef(CaseActorRef userRef) { CaseLogic logic = userRef.getCaseLogic(); String usersId = userRef.getId(); @@ -260,21 +251,18 @@ protected void resolveUserRef(CaseUserRef userRef) { net.addUserPermission(usersId, roleFactory.getProcessPermissions(logic)); } - @Transactional protected void resolveProcessEvents(ProcessEvents processEvents) { if (processEvents != null && processEvents.getEvent() != null) { net.setProcessEvents(createProcessEventsMap(processEvents.getEvent())); } } - @Transactional protected void resolveCaseEvents(CaseEvents caseEvents) { if (caseEvents != null && caseEvents.getEvent() != null) { net.setCaseEvents(createCaseEventsMap(caseEvents.getEvent())); } } - @Transactional protected void evaluateFunctions() { try { actionsCacheService.evaluateFunctions(functions); @@ -283,7 +271,6 @@ protected void evaluateFunctions() { } } - @Transactional protected void evaluateActions(String s, Action action) { try { actionsRunner.getActionCode(action, functions, true); @@ -292,7 +279,6 @@ protected void evaluateActions(String s, Action action) { } } - @Transactional protected void resolveActionRefs(String actionId, Action action) { Action referenced = actions.get(actionId); if (referenced == null) { @@ -302,13 +288,11 @@ protected void resolveActionRefs(String actionId, Action action) { action.setTrigger(referenced.getTrigger()); } - @Transactional protected void addI18N(I18N importI18N) { String locale = importI18N.getLocale(); importI18N.getI18NString().forEach(translation -> addTranslation(translation, locale)); } - @Transactional protected void addTranslation(I18NStringType i18NStringType, String locale) { String name = i18NStringType.getName(); I18nString translation = getI18n(name); @@ -319,7 +303,6 @@ protected void addTranslation(I18NStringType i18NStringType, String locale) { translation.addTranslation(locale, i18NStringType.getValue()); } - @Transactional protected void applyMapping(Mapping mapping) throws MissingIconKeyException { Transition transition = getTransition(mapping.getTransitionRef()); mapping.getRoleRef().forEach(roleRef -> addRoleLogic(transition, roleRef)); @@ -330,7 +313,6 @@ protected void applyMapping(Mapping mapping) throws MissingIconKeyException { mapping.getTrigger().forEach(trigger -> addTrigger(transition, trigger)); } - @Transactional protected void resolveDataActions(Data data) { String fieldId = data.getId(); if (data.getEvent() != null && !data.getEvent().isEmpty()) { @@ -368,7 +350,6 @@ private void addActionsToEvent(List actions, DataEventType type, Map actions = buildActionRefs(data.getActionRef()); @@ -388,7 +369,6 @@ protected Action fromActionRef(ActionRef actionRef) { return placeholder; } - @Transactional protected void resolveTransitionActions(com.netgrif.application.engine.importer.model.Transition trans) { if (trans.getDataRef() != null) { resolveDataRefActions(trans.getDataRef(), trans); @@ -402,7 +382,6 @@ protected void resolveTransitionActions(com.netgrif.application.engine.importer. } } - @Transactional protected void resolveDataRefActions(List dataRef, com.netgrif.application.engine.importer.model.Transition trans) { dataRef.forEach(ref -> { String fieldId = getField(ref.getId()).getStringId(); @@ -449,7 +428,6 @@ protected DataEvent createDefaultEvent(List actions, DataEventType type) return event; } - @Transactional protected void createArc(com.netgrif.application.engine.importer.model.Arc importArc) { Arc arc = arcFactory.getArc(importArc); arc.setImportId(importArc.getId()); @@ -477,15 +455,13 @@ protected void createArc(com.netgrif.application.engine.importer.model.Arc impor net.addArc(arc); } - @Transactional protected void createDataSet(Data importData) throws MissingIconKeyException { - Field field = fieldFactory.getField(importData, this); + Field field = fieldFactory.getField(importData, this); net.addDataSetField(field); fields.put(importData.getId(), field); } - @Transactional protected void createTransition(com.netgrif.application.engine.importer.model.Transition importTransition) throws MissingIconKeyException { transitionValidator.checkConflictingAttributes(importTransition, importTransition.getUsersRef(), importTransition.getUserRef(), "usersRef", "userRef"); transitionValidator.checkDeprecatedAttributes(importTransition); @@ -558,7 +534,6 @@ protected void createTransition(com.netgrif.application.engine.importer.model.Tr transitions.put(importTransition.getId(), transition); } - @Transactional protected void addAssignedUserPolicy(com.netgrif.application.engine.importer.model.Transition importTransition, Transition transition) { if (importTransition.getAssignedUser().isCancel() != null) { transition.getAssignedUserPolicy().put("cancel", importTransition.getAssignedUser().isCancel()); @@ -568,7 +543,6 @@ protected void addAssignedUserPolicy(com.netgrif.application.engine.importer.mod } } - @Transactional protected com.netgrif.application.engine.petrinet.domain.events.Event addEvent(String transitionId, com.netgrif.application.engine.importer.model.Event imported) { com.netgrif.application.engine.petrinet.domain.events.Event event = new com.netgrif.application.engine.petrinet.domain.events.Event(); event.setImportId(imported.getId()); @@ -581,7 +555,6 @@ protected com.netgrif.application.engine.petrinet.domain.events.Event addEvent(S return event; } - @Transactional protected com.netgrif.application.engine.petrinet.domain.events.ProcessEvent addProcessEvent(com.netgrif.application.engine.importer.model.ProcessEvent imported) { com.netgrif.application.engine.petrinet.domain.events.ProcessEvent event = new com.netgrif.application.engine.petrinet.domain.events.ProcessEvent(); event.setMessage(toI18NString(imported.getMessage())); @@ -593,7 +566,6 @@ protected com.netgrif.application.engine.petrinet.domain.events.ProcessEvent add return event; } - @Transactional protected com.netgrif.application.engine.petrinet.domain.events.CaseEvent addCaseEvent(com.netgrif.application.engine.importer.model.CaseEvent imported) { com.netgrif.application.engine.petrinet.domain.events.CaseEvent event = new com.netgrif.application.engine.petrinet.domain.events.CaseEvent(); event.setMessage(toI18NString(imported.getMessage())); @@ -644,7 +616,6 @@ protected List parsePhaseActions(String fieldId, EventPhaseType phase, D return actionList; } - @Transactional protected void addDefaultRole(Transition transition) { if (!net.isDefaultRoleEnabled() || isDefaultRoleReferenced(transition)) { return; @@ -656,7 +627,6 @@ protected void addDefaultRole(Transition transition) { transition.addRole(defaultRole.getStringId(), roleFactory.getPermissions(logic)); } - @Transactional protected void addAnonymousRole(Transition transition) { if (!net.isAnonymousRoleEnabled() || isAnonymousRoleReferenced(transition)) { return; @@ -667,7 +637,6 @@ protected void addAnonymousRole(Transition transition) { transition.addRole(anonymousRole.getStringId(), roleFactory.getPermissions(logic)); } - @Transactional protected void addDefaultPermissions() { if (!net.isDefaultRoleEnabled() || isDefaultRoleReferencedOnNet()) { return; @@ -680,7 +649,6 @@ protected void addDefaultPermissions() { net.addPermission(defaultRole.getStringId(), roleFactory.getProcessPermissions(logic)); } - @Transactional protected void addAnonymousPermissions() { if (!net.isAnonymousRoleEnabled() || isAnonymousRoleReferencedOnNet()) { return; @@ -692,7 +660,6 @@ protected void addAnonymousPermissions() { net.addPermission(anonymousRole.getStringId(), roleFactory.getProcessPermissions(logic)); } - @Transactional protected void addDataWithDefaultGroup(Transition transition, DataRef dataRef) throws MissingIconKeyException { DataGroup dataGroup = new DataGroup(); dataGroup.setImportId(transition.getImportId() + "_" + dataRef.getId() + "_" + System.currentTimeMillis()); @@ -709,7 +676,6 @@ protected void addDataWithDefaultGroup(Transition transition, DataRef dataRef) t addDataComponent(transition, dataRef); } - @Transactional protected void addDataGroup(Transition transition, com.netgrif.application.engine.importer.model.DataGroup importDataGroup, int index) throws MissingIconKeyException { String alignment = importDataGroup.getAlignment() != null ? importDataGroup.getAlignment().value() : ""; DataGroup dataGroup = new DataGroup(); @@ -738,7 +704,6 @@ protected void addDataGroup(Transition transition, com.netgrif.application.engin } } - @Transactional protected void addToTransaction(Transition transition, TransactionRef transactionRef) { Transaction transaction = getTransaction(transactionRef.getId()); if (transaction == null) { @@ -747,7 +712,6 @@ protected void addToTransaction(Transition transition, TransactionRef transactio transaction.addTransition(transition); } - @Transactional protected void addRoleLogic(Transition transition, RoleRef roleRef) { Logic logic = roleRef.getLogic(); String roleId = getRole(roleRef.getId()).getStringId(); @@ -765,8 +729,7 @@ protected void addRoleLogic(Transition transition, RoleRef roleRef) { transition.addRole(roleId, roleFactory.getPermissions(logic)); } - @Transactional - protected void addUserLogic(Transition transition, UserRef userRef) { + protected void addUserLogic(Transition transition, ActorRef userRef) { Logic logic = userRef.getLogic(); String userRefId = userRef.getId(); @@ -780,7 +743,6 @@ protected void addUserLogic(Transition transition, UserRef userRef) { transition.addUserRef(userRefId, roleFactory.getPermissions(logic)); } - @Transactional protected void addDataLogic(Transition transition, DataRef dataRef) { Logic logic = dataRef.getLogic(); try { @@ -800,7 +762,6 @@ protected void addDataLogic(Transition transition, DataRef dataRef) { } } - @Transactional protected void addDataLayout(Transition transition, DataRef dataRef) { Layout layout = dataRef.getLayout(); try { @@ -831,7 +792,6 @@ protected void addDataLayout(Transition transition, DataRef dataRef) { } } - @Transactional protected void addDataComponent(Transition transition, DataRef dataRef) throws MissingIconKeyException { String fieldId = getField(dataRef.getId()).getStringId(); Component component = null; @@ -841,7 +801,6 @@ protected void addDataComponent(Transition transition, DataRef dataRef) throws M transition.addDataSet(fieldId, null, null, null, component); } - @Transactional protected Map buildEvents(String fieldId, List events, String transitionId) { Map parsedEvents = new HashMap<>(); @@ -897,7 +856,6 @@ protected com.netgrif.application.engine.petrinet.domain.events.DataEvent create return dataEvent; } - @Transactional protected List buildActions(List imported, String fieldId, String transitionId) { return imported.stream() .map(action -> parseAction(fieldId, transitionId, action)) @@ -964,7 +922,6 @@ protected boolean containsParams(String definition) { return definition.matches("[\\W\\w\\s]*[\\w]*:[\\s]*[ft].[\\w]+;[\\w\\W\\s]*"); } - @Transactional protected void parseObjectIds(Action action, String fieldId, String transitionId, String definition) { try { Map ids = parseParams(definition); @@ -1020,14 +977,12 @@ protected String getFieldId(String importId) { } } - @Transactional protected void addTrigger(Transition transition, com.netgrif.application.engine.importer.model.Trigger importTrigger) { Trigger trigger = triggerFactory.buildTrigger(importTrigger); transition.addTrigger(trigger); } - @Transactional protected void createPlace(com.netgrif.application.engine.importer.model.Place importPlace) { Place place = new Place(); place.setImportId(importPlace.getId()); @@ -1044,7 +999,6 @@ protected void createPlace(com.netgrif.application.engine.importer.model.Place i places.put(importPlace.getId(), place); } - @Transactional protected void createRole(Role importRole) { if (importRole.getId().equals(ProcessRole.DEFAULT_ROLE)) { throw new IllegalArgumentException("Role ID '" + ProcessRole.DEFAULT_ROLE + "' is a reserved identifier, roles with this ID cannot be defined!"); @@ -1115,7 +1069,6 @@ protected Map mapping; + + public ConfigurationTemplateOutcome() { + this.mapping = new HashMap<>(); + } + + public ConfigurationTemplateOutcome(ToDataSetOutcome toDataSetOutcome) { + this(); + if (toDataSetOutcome != null) { + toDataSetOutcome.getDataSet() + .forEach((fieldId, fieldMap) -> this.mapping.put(fieldId, fieldMap.get("value"))); + } + } + +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/FilterBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/FilterBody.java index de048064e33..bfa7f29634c 100644 --- a/src/main/java/com/netgrif/application/engine/menu/domain/FilterBody.java +++ b/src/main/java/com/netgrif/application/engine/menu/domain/FilterBody.java @@ -1,74 +1,33 @@ package com.netgrif.application.engine.menu.domain; -import com.netgrif.application.engine.petrinet.domain.I18nString; import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; -import com.netgrif.application.engine.startup.DefaultFiltersRunner; -import com.netgrif.application.engine.workflow.domain.Case; import com.netgrif.application.engine.workflow.service.interfaces.IDataService; import lombok.Data; import lombok.NoArgsConstructor; import java.util.HashMap; -import java.util.List; import java.util.Map; @Data @NoArgsConstructor public class FilterBody { - private Case filter; - private I18nString title; private String query; - private String type; - private List allowedNets; - private String icon; - private String visibility; - private Map metadata; - - public FilterBody(Case filterCase) { - this.filter = filterCase; - } - - /** - * Gets default metadata with provided filter type - * - * @param type type of the filter - * - * @return metadata containing filter type as map - * */ - public static Map getDefaultMetadata(String type) { - Map resultMap = new HashMap<>(); - - resultMap.put("searchCategories", List.of()); - resultMap.put("predicateMetadata", List.of()); - resultMap.put("filterType", type); - resultMap.put("defaultSearchCategories", true); - resultMap.put("inheritAllowedNets", false); - - return resultMap; - } + private FieldType type; /** * Transforms attributes into dataSet for {@link IDataService#setData} * * @return {@link ToDataSetOutcome} object with dataSet * */ - public ToDataSetOutcome toDataSet() { - ToDataSetOutcome outcome = new ToDataSetOutcome(); - - outcome.putDataSetEntry(DefaultFiltersRunner.FILTER_TYPE_FIELD_ID, FieldType.ENUMERATION_MAP, this.type); - outcome.putDataSetEntry(DefaultFiltersRunner.FILTER_VISIBILITY_FIELD_ID, FieldType.ENUMERATION_MAP, this.visibility); - outcome.putDataSetEntry(DefaultFiltersRunner.FILTER_I18N_TITLE_FIELD_ID, FieldType.I18N, this.title); - Map metadata = this.metadata; - if (metadata == null) { - metadata = getDefaultMetadata(this.type); + public ToDataSetOutcome toDataSet(ToDataSetOutcome viewDataSetOutcome, String filterFieldId) { + Map dataSetValues = new HashMap<>(); + if (this.type == null) { + throw new IllegalArgumentException("Filter type is not provided"); } - outcome.getDataSet().put(DefaultFiltersRunner.FILTER_FIELD_ID, Map.of( - "type", "filter", - "value", this.query, - "allowedNets", this.allowedNets, - "filterMetadata", metadata - )); + dataSetValues.put("type", this.type.getName()); + dataSetValues.put("value", this.query); + viewDataSetOutcome.getDataSet().put(filterFieldId, dataSetValues); - return outcome; + return viewDataSetOutcome; } } diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemBody.java index 9637f9ddeb8..02dde589073 100644 --- a/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemBody.java +++ b/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemBody.java @@ -22,6 +22,7 @@ public class MenuItemBody { private String uri; private String identifier; + private String configurationTemplateIdentifier; private String menuIcon = "filter_none"; private I18nString menuName; @@ -31,7 +32,7 @@ public class MenuItemBody { private String customViewSelector; private boolean isAutoSelect = false; - private boolean useTabbedView; + private boolean useTabbedView = true; private String tabIcon; private boolean useTabIcon = true; private I18nString tabName; @@ -108,8 +109,14 @@ public void setTabName(String name) { } public void setView(ViewBody viewBody) { - this.view = viewBody; - this.useTabbedView = viewBody == null || viewBody.getViewType().isTabbed(); + if (viewBody != null) { + this.view = viewBody; + MenuItemViewType viewType = viewBody.getViewType(); + if (viewType.isTabbed() != viewType.isUntabbed()) { + // if isTabbed == isUntabbed we cannot determine the result value + this.useTabbedView = viewType.isTabbed(); + } + } } /** @@ -157,10 +164,16 @@ public ToDataSetOutcome toDataSet(String parentId, String nodePath, Case viewCas if (nodePath != null) { outcome.putDataSetEntry(MenuItemConstants.FIELD_NODE_PATH, FieldType.TEXT, nodePath); } - outcome.putDataSetEntry(MenuItemConstants.FIELD_MENU_NAME, FieldType.I18N, this.menuName); + if (this.menuName == null) { + outcome.putDataSetEntry(MenuItemConstants.FIELD_MENU_NAME, FieldType.I18N, new I18nString(this.identifier)); + } else { + outcome.putDataSetEntry(MenuItemConstants.FIELD_MENU_NAME, FieldType.I18N, this.menuName); + } outcome.putDataSetEntry(MenuItemConstants.FIELD_MENU_ICON, FieldType.TEXT, this.menuIcon); outcome.putDataSetEntry(MenuItemConstants.FIELD_USE_TABBED_VIEW, FieldType.BOOLEAN, this.useTabbedView); - outcome.putDataSetEntry(MenuItemConstants.FIELD_TAB_NAME, FieldType.I18N, this.tabName); + if (this.tabName != null) { + outcome.putDataSetEntry(MenuItemConstants.FIELD_TAB_NAME, FieldType.I18N, this.tabName); + } outcome.putDataSetEntry(MenuItemConstants.FIELD_TAB_ICON, FieldType.TEXT, this.tabIcon); if (this.identifier != null) { outcome.putDataSetEntry(MenuItemConstants.FIELD_IDENTIFIER, FieldType.TEXT, this.getIdentifier()); @@ -173,7 +186,27 @@ public ToDataSetOutcome toDataSet(String parentId, String nodePath, Case viewCas outcome.putDataSetEntry(MenuItemConstants.FIELD_IS_AUTO_SELECT, FieldType.BOOLEAN, this.isAutoSelect); outcome.putDataSetEntryOptions(MenuItemConstants.FIELD_ALLOWED_ROLES, FieldType.MULTICHOICE_MAP, this.allowedRoles); outcome.putDataSetEntryOptions(MenuItemConstants.FIELD_BANNED_ROLES, FieldType.MULTICHOICE_MAP, this.bannedRoles); + outcome.putDataSetEntry(MenuItemConstants.FIELD_CONFIGURATION_TEMPLATES, FieldType.ENUMERATION_MAP, this.configurationTemplateIdentifier); + + outcome = toDataSetWithView(viewCase, outcome); + return outcome; + } + + /** + * Transforms minimal attributes into dataSet for view configuration by template. + * + * @param viewCase case instance of view + * @return {@link ToDataSetOutcome} object with dataSet containing only view-related fields + */ + public ToDataSetOutcome toDataSetByConfigTemplate(Case viewCase) { + ToDataSetOutcome outcome = new ToDataSetOutcome(); + outcome.putDataSetEntry(MenuItemConstants.FIELD_USE_TABBED_VIEW, FieldType.BOOLEAN, this.useTabbedView); + outcome.putDataSetEntry(MenuItemConstants.FIELD_USE_CUSTOM_VIEW, FieldType.BOOLEAN, this.useCustomView); + return toDataSetWithView(viewCase, outcome); + } + + protected ToDataSetOutcome toDataSetWithView(Case viewCase, ToDataSetOutcome outcome) { if (viewCase != null) { outcome.putDataSetEntry(MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE, FieldType.ENUMERATION_MAP, this.view.getViewType().getIdentifier()); @@ -181,8 +214,9 @@ public ToDataSetOutcome toDataSet(String parentId, String nodePath, Case viewCas List.of(viewCase.getStringId())); String taskId = MenuItemUtils.findTaskIdInCase(viewCase, ViewConstants.TRANS_SETTINGS_ID); outcome.putDataSetEntry(MenuItemConstants.FIELD_VIEW_CONFIGURATION_FORM, FieldType.TASK_REF, List.of(taskId)); + String allDataTaskId = MenuItemUtils.findTaskIdInCase(viewCase, ViewConstants.TRANS_ALL_MENU_DATA_ID); + outcome.putDataSetEntry(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM, FieldType.TASK_REF, List.of(allDataTaskId)); } - return outcome; } } diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemConstants.java index d6ac1a37afc..60992401417 100644 --- a/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemConstants.java +++ b/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemConstants.java @@ -28,8 +28,17 @@ public class MenuItemConstants { public static final String FIELD_IS_AUTO_SELECT = "is_auto_select"; public static final String FIELD_VIEW_CONFIGURATION_ID = "view_configuration_id"; public static final String FIELD_VIEW_CONFIGURATION_FORM = "view_configuration_form"; + public static final String FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM = "view_configuration_all_data_form"; + public static final String FIELD_CONFIGURATION_TEMPLATES = "configuration_templates"; public static final String TRANS_SETTINGS_ID = "item_settings"; + public static final String TRANS_SYS_INIT_ID = "system_initialize"; public static final String TRANS_INIT_ID = "initialize"; public static final String TRANS_SYNC_ID = "data_sync"; + public static final String TRANS_ALL_MENU_DATA = "all_menu_data"; + + public static final String PROCESS_IDENTIFIER = "menu_item"; + + public static final String IDENTIFIER_INDEX_NAME = "menuItemIdentifierIdx"; + public static final String NODE_PATH_INDEX_NAME = "menuItemNodePathIdx"; } diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemView.java b/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemViewType.java similarity index 54% rename from src/main/java/com/netgrif/application/engine/menu/domain/MenuItemView.java rename to src/main/java/com/netgrif/application/engine/menu/domain/MenuItemViewType.java index 1bdf5a43d54..bdf38961bee 100644 --- a/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemView.java +++ b/src/main/java/com/netgrif/application/engine/menu/domain/MenuItemViewType.java @@ -13,17 +13,19 @@ * Here is listed and configured every configuration process available for menu items. * */ @Getter -public enum MenuItemView { - TABBED_CASE_VIEW(new I18nString("Tabbed case view", Map.of("sk", "Zobrazenie prípadov v taboch", - "de", "Fallansicht mit Registerkarten")), "tabbed_case_view", List.of("tabbed_task_view"), - true, true), - TABBED_TASK_VIEW(new I18nString("Tabbed task view", Map.of("sk", "Zobrazenie úloh v taboch", - "de", "Aufgabenansicht mit Registerkarten")), "tabbed_task_view", List.of(), true, true), - TABBED_TICKET_VIEW(new I18nString("Tabbed ticket view", Map.of("sk", "Tiketové zobrazenie v taboch", - "de", "Ticketansicht mit Registerkarten")), "tabbed_ticket_view", - List.of("tabbed_single_task_view"), true, true), - TABBED_SINGLE_TASK_VIEW(new I18nString("Tabbed single task view", Map.of("sk", "Zobrazenie jednej úlohy v taboch", - "de", "Einzelaufgabenansicht mit Registerkarten")), "tabbed_single_task_view", List.of(), true, false); +public enum MenuItemViewType { + CASE_VIEW(new I18nString("Case view", + Map.of("sk", "Zobrazenie prípadov", "de", "Fallansicht")), + "case_view", List.of("task_view"), true, true, true), + TASK_VIEW(new I18nString("Task view", + Map.of("sk", "Zobrazenie úloh", "de", "Aufgabenansicht")), + "task_view", List.of(), true, true, true), + TABBED_TICKET_VIEW(new I18nString("Tabbed ticket view", + Map.of("sk", "Tiketové zobrazenie v taboch", "de", "Ticketansicht mit Registerkarten")), + "tabbed_ticket_view", List.of("single_task_view"), true, false, true), + SINGLE_TASK_VIEW(new I18nString("Single task view", + Map.of("sk", "Zobrazenie jednej úlohy", "de", "Einzelaufgabenansicht")), + "single_task_view", List.of(), true, true, true); private final I18nString name; private final String identifier; @@ -32,25 +34,28 @@ public enum MenuItemView { * */ private final List allowedAssociatedViews; private final boolean isTabbed; + private final boolean isUntabbed; /** * if false, the view cannot be used as first configuration of the menu_item, but can be used as secondary * (associated to another view) * */ private final boolean isPrimary; - MenuItemView(I18nString name, String identifier, List allowedAssociatedViews, boolean isTabbed, boolean isPrimary) { + MenuItemViewType(I18nString name, String identifier, List allowedAssociatedViews, boolean isTabbed, + boolean isUntabbed, boolean isPrimary) { this.name = name; this.identifier = identifier; this.allowedAssociatedViews = allowedAssociatedViews; this.isTabbed = isTabbed; + this.isUntabbed = isUntabbed; this.isPrimary = isPrimary; } /** * Builds enum value by the view identifier * */ - public static MenuItemView fromIdentifier(String identifier) { - for (MenuItemView view : MenuItemView.values()) { + public static MenuItemViewType fromIdentifier(String identifier) { + for (MenuItemViewType view : MenuItemViewType.values()) { if (view.identifier.equals(identifier)) { return view; } @@ -66,9 +71,9 @@ public static MenuItemView fromIdentifier(String identifier) { * * @return List of views based on {@link #isTabbed} * */ - public static List findAllByIsTabbedAndIsPrimary(boolean isTabbed, boolean isPrimary) { - return Arrays.stream(MenuItemView.values()) - .filter(view -> view.isTabbed == isTabbed && view.isPrimary == isPrimary) + public static List findAllByIsTabbedAndIsPrimary(boolean isTabbed, boolean isPrimary) { + return Arrays.stream(MenuItemViewType.values()) + .filter(view -> (view.isTabbed == isTabbed || view.isUntabbed != isTabbed) && view.isPrimary == isPrimary) .collect(Collectors.toList()); } @@ -80,10 +85,10 @@ public static List findAllByIsTabbedAndIsPrimary(boolean isTabbed, * * @return List of views based on {@link #isTabbed} and {@link #allowedAssociatedViews} * */ - public static List findAllByIsTabbedAndParentIdentifier(boolean isTabbed, String parentIdentifier) { - MenuItemView parentView = fromIdentifier(parentIdentifier); - return Arrays.stream(MenuItemView.values()) - .filter(view -> view.isTabbed == isTabbed + public static List findAllByIsTabbedAndParentIdentifier(boolean isTabbed, String parentIdentifier) { + MenuItemViewType parentView = fromIdentifier(parentIdentifier); + return Arrays.stream(MenuItemViewType.values()) + .filter(view -> (view.isTabbed == isTabbed || view.isUntabbed != isTabbed) && parentView.getAllowedAssociatedViews().contains(view.identifier)) .collect(Collectors.toList()); } diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/CaseViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/CaseViewBody.java new file mode 100644 index 00000000000..6a47b3b45b3 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/CaseViewBody.java @@ -0,0 +1,114 @@ +package com.netgrif.application.engine.menu.domain.configurations; + +import com.netgrif.application.engine.menu.domain.MenuItemViewType; +import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; +import com.netgrif.application.engine.petrinet.domain.I18nString; +import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class CaseViewBody extends ViewBody { + private String viewSearchType = "fulltext_advanced"; + private I18nString createCaseButtonTitle; + private String createCaseButtonIcon = "add"; + private boolean requireTitleInCreation = true; + private boolean showCreateCaseButton = true; + private String bannedNetsInCreation; + private boolean showMoreMenu = false; + private boolean allowHeaderTableMode = true; + private List headersMode = new ArrayList<>(List.of("sort", "edit", "search")); + private String headersDefaultMode = "sort"; + private List defaultHeaders; + private boolean headerModeChangeable = true; + private boolean useDefaultHeaders = true; + private I18nString emptyContentText; + private String emptyContentIcon; + private boolean allowExport; + private boolean allAllowedNets = true; + private List allowedNets; + private boolean inheritAllowedNets = true; + + private ViewBody chainedView; + + @Override + public ViewBody getAssociatedViewBody() { + return this.chainedView; + } + + @Override + public MenuItemViewType getViewType() { + return MenuItemViewType.CASE_VIEW; + } + + @Override + public String getFilterFieldId() { + return CaseViewConstants.FIELD_FILTER; + } + + @Override + public FieldType getFilterType() { + return FieldType.CASE_FILTER; + } + + @Override + protected ToDataSetOutcome toDataSetInternal(ToDataSetOutcome outcome) { + + outcome.putDataSetEntry(CaseViewConstants.FIELD_VIEW_SEARCH_TYPE, FieldType.ENUMERATION_MAP, + this.viewSearchType); + if (this.createCaseButtonTitle != null) { + outcome.putDataSetEntry(CaseViewConstants.FIELD_CREATE_CASE_BUTTON_TITLE, FieldType.I18N, + this.createCaseButtonTitle); + } + outcome.putDataSetEntry(CaseViewConstants.FIELD_CREATE_CASE_BUTTON_ICON, FieldType.TEXT, + this.createCaseButtonIcon); + outcome.putDataSetEntry(CaseViewConstants.FIELD_REQUIRE_TITLE_IN_CREATION, FieldType.BOOLEAN, + this.requireTitleInCreation); + outcome.putDataSetEntry(CaseViewConstants.FIELD_SHOW_CREATE_CASE_BUTTON, FieldType.BOOLEAN, + this.showCreateCaseButton); + outcome.putDataSetEntry(CaseViewConstants.FIELD_BANNED_NETS_IN_CREATION, FieldType.TEXT, + this.bannedNetsInCreation); + outcome.putDataSetEntry(CaseViewConstants.FIELD_SHOW_MORE_MENU, FieldType.BOOLEAN, + this.showMoreMenu); + outcome.putDataSetEntry(CaseViewConstants.FIELD_ALLOW_HEADER_TABLE_MODE, FieldType.BOOLEAN, + this.allowHeaderTableMode); + outcome.putDataSetEntry(CaseViewConstants.FIELD_HEADERS_MODE, FieldType.MULTICHOICE_MAP, + this.headersMode == null ? new ArrayList<>() : this.headersMode); + outcome.putDataSetEntry(CaseViewConstants.FIELD_HEADERS_DEFAULT_MODE, FieldType.ENUMERATION_MAP, + this.headersDefaultMode); + if (this.defaultHeaders != null) { + outcome.putDataSetEntry(CaseViewConstants.FIELD_DEFAULT_HEADERS, FieldType.STRING_COLLECTION, + this.defaultHeaders); + } + outcome.putDataSetEntry(CaseViewConstants.FIELD_IS_HEADER_MODE_CHANGEABLE, FieldType.BOOLEAN, + this.headerModeChangeable); + outcome.putDataSetEntry(CaseViewConstants.FIELD_USE_DEFAULT_HEADERS, FieldType.BOOLEAN, + this.useDefaultHeaders); + if (this.emptyContentText != null) { + outcome.putDataSetEntry(CaseViewConstants.FIELD_EMPTY_CONTENT_TEXT, FieldType.I18N, + this.emptyContentText); + } + outcome.putDataSetEntry(CaseViewConstants.FIELD_EMPTY_CONTENT_ICON, FieldType.TEXT, + this.emptyContentIcon); + outcome.putDataSetEntry(CaseViewConstants.FIELD_ALLOW_EXPORT, FieldType.BOOLEAN, + this.allowExport); + + outcome.putDataSetEntry(CaseViewConstants.FIELD_ALL_ALLOWED_NETS, FieldType.BOOLEAN, + this.allAllowedNets); + if (this.allowedNets != null) { + outcome.putDataSetEntry(CaseViewConstants.FIELD_ALLOWED_NETS, FieldType.STRING_COLLECTION, + this.allowedNets); + } + outcome.putDataSetEntry(CaseViewConstants.FIELD_INHERIT_ALLOWED_NETS, FieldType.BOOLEAN, + this.inheritAllowedNets); + + return outcome; + } +} + diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/CaseViewConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/CaseViewConstants.java new file mode 100644 index 00000000000..44db426e1b5 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/CaseViewConstants.java @@ -0,0 +1,27 @@ +package com.netgrif.application.engine.menu.domain.configurations; + +/** + * Here are declared constants of process case_view_configuration.xml. + */ +public class CaseViewConstants extends ViewConstants { + public static final String FIELD_DEFAULT_HEADERS = "case_default_headers"; + public static final String FIELD_REQUIRE_TITLE_IN_CREATION = "require_title_in_creation"; + public static final String FIELD_VIEW_SEARCH_TYPE = "case_view_search_type"; + public static final String FIELD_CREATE_CASE_BUTTON_TITLE = "create_case_button_title"; + public static final String FIELD_CREATE_CASE_BUTTON_ICON = "create_case_button_icon"; + public static final String FIELD_BANNED_NETS_IN_CREATION = "banned_nets_in_creation"; + public static final String FIELD_SHOW_CREATE_CASE_BUTTON = "show_create_case_button"; + public static final String FIELD_SHOW_MORE_MENU = "case_show_more_menu"; + public static final String FIELD_ALLOW_HEADER_TABLE_MODE = "case_allow_header_table_mode"; + public static final String FIELD_HEADERS_MODE = "case_headers_mode"; + public static final String FIELD_HEADERS_DEFAULT_MODE = "case_headers_default_mode"; + public static final String FIELD_IS_HEADER_MODE_CHANGEABLE = "case_is_header_mode_changeable"; + public static final String FIELD_USE_DEFAULT_HEADERS = "use_case_default_headers"; + public static final String FIELD_EMPTY_CONTENT_TEXT = "case_empty_content_text"; + public static final String FIELD_EMPTY_CONTENT_ICON = "case_empty_content_icon"; + public static final String FIELD_FILTER = "case_filter"; + public static final String FIELD_ALLOW_EXPORT = "case_allow_export"; + public static final String FIELD_ALL_ALLOWED_NETS = "case_all_allowed_nets"; + public static final String FIELD_ALLOWED_NETS = "case_allowed_nets"; + public static final String FIELD_INHERIT_ALLOWED_NETS = "case_inherit_allowed_nets"; +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/SingleTaskViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/SingleTaskViewBody.java new file mode 100644 index 00000000000..1b4e3531adb --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/SingleTaskViewBody.java @@ -0,0 +1,43 @@ +package com.netgrif.application.engine.menu.domain.configurations; + +import com.netgrif.application.engine.menu.domain.MenuItemViewType; +import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; +import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class SingleTaskViewBody extends ViewBody { + private boolean showPageHeader = true; + private boolean showPageFooter = false; + + @Override + public ViewBody getAssociatedViewBody() { + return null; + } + + @Override + public MenuItemViewType getViewType() { + return MenuItemViewType.SINGLE_TASK_VIEW; + } + + @Override + public String getFilterFieldId() { + return SingleTaskViewConstants.FIELD_FILTER; + } + + @Override + public FieldType getFilterType() { + return FieldType.TASK_FILTER; + } + + @Override + protected ToDataSetOutcome toDataSetInternal(ToDataSetOutcome outcome) { + outcome.putDataSetEntry(SingleTaskViewConstants.FIELD_SHOW_PAGE_HEADER, FieldType.BOOLEAN, this.showPageHeader); + outcome.putDataSetEntry(SingleTaskViewConstants.FIELD_SHOW_PAGE_FOOTER, FieldType.BOOLEAN, this.showPageFooter); + return outcome; + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/SingleTaskViewConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/SingleTaskViewConstants.java new file mode 100644 index 00000000000..d251523ae8f --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/SingleTaskViewConstants.java @@ -0,0 +1,7 @@ +package com.netgrif.application.engine.menu.domain.configurations; + +public class SingleTaskViewConstants extends ViewConstants { + public static final String FIELD_SHOW_PAGE_HEADER = "show_page_header"; + public static final String FIELD_SHOW_PAGE_FOOTER = "show_page_footer"; + public static final String FIELD_FILTER = "task_filter"; +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedCaseViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedCaseViewBody.java deleted file mode 100644 index 5f18b2920cb..00000000000 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedCaseViewBody.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.netgrif.application.engine.menu.domain.configurations; - -import com.netgrif.application.engine.menu.domain.MenuItemView; -import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; -import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; - -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class TabbedCaseViewBody extends ViewBody { - private String viewSearchType = "fulltext_advanced"; - private String createCaseButtonTitle; - private String createCaseButtonIcon = "add"; - private boolean requireTitleInCreation = true; - private boolean showCreateCaseButton = true; - private String bannedNetsInCreation; - private boolean showMoreMenu = false; - private boolean allowHeaderTableMode = true; - private List headersMode = new ArrayList<>(List.of("sort", "edit", "search")); - private String headersDefaultMode = "sort"; - private List defaultHeaders; - private boolean isHeaderModeChangeable = true; - private boolean useDefaultHeaders = true; - - private ViewBody chainedView; - - @Override - public ViewBody getAssociatedViewBody() { - return this.chainedView; - } - - @Override - public MenuItemView getViewType() { - return MenuItemView.TABBED_CASE_VIEW; - } - - @Override - protected ToDataSetOutcome toDataSetInternal(ToDataSetOutcome outcome) { - - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_VIEW_SEARCH_TYPE, FieldType.ENUMERATION_MAP, - this.viewSearchType); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_CREATE_CASE_BUTTON_TITLE, FieldType.TEXT, - this.createCaseButtonTitle); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_CREATE_CASE_BUTTON_ICON, FieldType.TEXT, - this.createCaseButtonIcon); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_REQUIRE_TITLE_IN_CREATION, FieldType.BOOLEAN, - this.requireTitleInCreation); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_SHOW_CREATE_CASE_BUTTON, FieldType.BOOLEAN, - this.showCreateCaseButton); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_BANNED_NETS_IN_CREATION, FieldType.TEXT, - this.bannedNetsInCreation); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_SHOW_MORE_MENU, FieldType.BOOLEAN, - this.showMoreMenu); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_ALLOW_HEADER_TABLE_MODE, FieldType.BOOLEAN, - this.allowHeaderTableMode); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_HEADERS_MODE, FieldType.MULTICHOICE_MAP, - this.headersMode == null ? new ArrayList<>() : this.headersMode); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_HEADERS_DEFAULT_MODE, FieldType.ENUMERATION_MAP, - this.headersDefaultMode); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_DEFAULT_HEADERS, FieldType.TEXT, - this.defaultHeaders != null ? String.join(",", this.defaultHeaders) : null); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_IS_HEADER_MODE_CHANGEABLE, FieldType.BOOLEAN, - this.isHeaderModeChangeable); - outcome.putDataSetEntry(TabbedCaseViewConstants.FIELD_USE_CASE_DEFAULT_HEADERS, FieldType.BOOLEAN, - this.useDefaultHeaders); - - return outcome; - } -} - diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedCaseViewConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedCaseViewConstants.java deleted file mode 100644 index b5c8ef2361b..00000000000 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedCaseViewConstants.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.netgrif.application.engine.menu.domain.configurations; - -/** - * Here are declared constants of process tabbed_case_view_configuration.xml. - */ -public class TabbedCaseViewConstants extends ViewConstants { - public static final String FIELD_NEW_FILTER_ID = "new_filter_id"; - public static final String FIELD_DEFAULT_HEADERS = "default_headers"; - public static final String FIELD_REQUIRE_TITLE_IN_CREATION = "require_title_in_creation"; - public static final String FIELD_VIEW_SEARCH_TYPE = "view_search_type"; - public static final String FIELD_CREATE_CASE_BUTTON_TITLE = "create_case_button_title"; - public static final String FIELD_CREATE_CASE_BUTTON_ICON = "create_case_button_icon"; - public static final String FIELD_BANNED_NETS_IN_CREATION = "banned_nets_in_creation"; - public static final String FIELD_SHOW_CREATE_CASE_BUTTON = "show_create_case_button"; - public static final String FIELD_SHOW_MORE_MENU = "show_more_menu"; - public static final String FIELD_ALLOW_HEADER_TABLE_MODE = "allow_header_table_mode"; - public static final String FIELD_HEADERS_MODE = "headers_mode"; - public static final String FIELD_HEADERS_DEFAULT_MODE = "headers_default_mode"; - public static final String FIELD_IS_HEADER_MODE_CHANGEABLE = "is_header_mode_changeable"; - public static final String FIELD_USE_CASE_DEFAULT_HEADERS = "use_case_default_headers"; -} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedSingleTaskViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedSingleTaskViewBody.java deleted file mode 100644 index fa58689c976..00000000000 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedSingleTaskViewBody.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.netgrif.application.engine.menu.domain.configurations; - -import com.netgrif.application.engine.menu.domain.MenuItemView; -import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; -import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class TabbedSingleTaskViewBody extends ViewBody { - private String transitionId; - - @Override - public ViewBody getAssociatedViewBody() { - return null; - } - - @Override - public MenuItemView getViewType() { - return MenuItemView.TABBED_SINGLE_TASK_VIEW; - } - - @Override - protected ToDataSetOutcome toDataSetInternal(ToDataSetOutcome outcome) { - outcome.putDataSetEntry(TabbedSingleTaskViewConstants.FIELD_TRANSITION_ID, FieldType.TEXT, this.transitionId); - return outcome; - } -} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedSingleTaskViewConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedSingleTaskViewConstants.java deleted file mode 100644 index c0d6949b328..00000000000 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedSingleTaskViewConstants.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.netgrif.application.engine.menu.domain.configurations; - -public class TabbedSingleTaskViewConstants extends ViewConstants { - public static final String FIELD_TRANSITION_ID = "transition_id"; -} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTaskViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTaskViewBody.java deleted file mode 100644 index 0fabe6940fe..00000000000 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTaskViewBody.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.netgrif.application.engine.menu.domain.configurations; - -import com.netgrif.application.engine.menu.domain.MenuItemView; -import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; -import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; -import com.netgrif.application.engine.workflow.domain.Case; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.util.ArrayList; -import java.util.List; - -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class TabbedTaskViewBody extends ViewBody { - private Case filter; - private boolean mergeFilters = true; - private String viewSearchType = "fulltext_advanced"; - private List headersMode = new ArrayList<>(List.of("sort", "edit")); - private String headersDefaultMode = "sort"; - private boolean isHeaderModeChangeable = true; - private boolean allowHeaderTableMode = true; - private boolean useDefaultHeaders = true; - private List defaultHeaders; - private boolean showMoreMenu = true; - - @Override - public ViewBody getAssociatedViewBody() { - return null; - } - - @Override - public MenuItemView getViewType() { - return MenuItemView.TABBED_TASK_VIEW; - } - - @Override - protected ToDataSetOutcome toDataSetInternal(ToDataSetOutcome outcome) { - - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_MERGE_FILTERS, FieldType.BOOLEAN, - this.mergeFilters); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_VIEW_SEARCH_TYPE, FieldType.ENUMERATION_MAP, - this.viewSearchType); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_HEADERS_MODE, FieldType.MULTICHOICE_MAP, - this.headersMode == null ? new ArrayList<>() : this.headersMode); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_HEADERS_DEFAULT_MODE, FieldType.ENUMERATION_MAP, - this.headersDefaultMode); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_IS_HEADER_MODE_CHANGEABLE, FieldType.BOOLEAN, - this.isHeaderModeChangeable); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_ALLOW_HEADER_TABLE_MODE, FieldType.BOOLEAN, - this.allowHeaderTableMode); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_USE_DEFAULT_HEADERS, FieldType.BOOLEAN, - this.useDefaultHeaders); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_DEFAULT_HEADERS, FieldType.TEXT, - this.defaultHeaders != null ? String.join(",", this.defaultHeaders) : null); - outcome.putDataSetEntry(TabbedTaskViewConstants.FIELD_SHOW_MORE_MENU, FieldType.BOOLEAN, - this.showMoreMenu); - - return outcome; - } -} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTaskViewConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTaskViewConstants.java deleted file mode 100644 index f895558fa77..00000000000 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTaskViewConstants.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.netgrif.application.engine.menu.domain.configurations; - -/** - * Here are declared constants of process tabbed_task_view_configuration.xml. - */ -public class TabbedTaskViewConstants extends ViewConstants { - public static final String FIELD_MERGE_FILTERS = "merge_filters"; - public static final String FIELD_VIEW_SEARCH_TYPE = "view_search_type"; - public static final String FIELD_DEFAULT_HEADERS = "default_headers"; - public static final String FIELD_HEADERS_MODE = "headers_mode"; - public static final String FIELD_HEADERS_DEFAULT_MODE = "headers_default_mode"; - public static final String FIELD_IS_HEADER_MODE_CHANGEABLE = "is_header_mode_changeable"; - public static final String FIELD_ALLOW_HEADER_TABLE_MODE = "allow_header_table_mode"; - public static final String FIELD_USE_DEFAULT_HEADERS = "use_default_headers"; - public static final String FIELD_SHOW_MORE_MENU = "show_more_menu"; -} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTicketViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTicketViewBody.java index f0aafd54b65..7f898695be2 100644 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTicketViewBody.java +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TabbedTicketViewBody.java @@ -1,7 +1,8 @@ package com.netgrif.application.engine.menu.domain.configurations; -import com.netgrif.application.engine.menu.domain.MenuItemView; +import com.netgrif.application.engine.menu.domain.MenuItemViewType; import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; +import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -19,8 +20,18 @@ public ViewBody getAssociatedViewBody() { } @Override - public MenuItemView getViewType() { - return MenuItemView.TABBED_TICKET_VIEW; + public MenuItemViewType getViewType() { + return MenuItemViewType.TABBED_TICKET_VIEW; + } + + @Override + public String getFilterFieldId() { + return ""; + } + + @Override + public FieldType getFilterType() { + return null; } @Override diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TaskViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TaskViewBody.java new file mode 100644 index 00000000000..4e8e09456bd --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TaskViewBody.java @@ -0,0 +1,94 @@ +package com.netgrif.application.engine.menu.domain.configurations; + +import com.netgrif.application.engine.menu.domain.MenuItemViewType; +import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; +import com.netgrif.application.engine.petrinet.domain.I18nString; +import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +public class TaskViewBody extends ViewBody { + private boolean mergeFilters = true; + private String viewSearchType = "fulltext_advanced"; + private List headersMode = new ArrayList<>(List.of("sort", "edit")); + private String headersDefaultMode = "sort"; + private boolean isHeaderModeChangeable = true; + private boolean allowHeaderTableMode = true; + private boolean useDefaultHeaders = true; + private List defaultHeaders; + private boolean showMoreMenu = true; + private I18nString emptyContentText; + private String emptyContentIcon; + private boolean allAllowedNets = true; + private List allowedNets; + private boolean inheritAllowedNets = true; + + @Override + public ViewBody getAssociatedViewBody() { + return null; + } + + @Override + public MenuItemViewType getViewType() { + return MenuItemViewType.TASK_VIEW; + } + + @Override + public String getFilterFieldId() { + return TaskViewConstants.FIELD_FILTER; + } + + @Override + public FieldType getFilterType() { + return FieldType.TASK_FILTER; + } + + @Override + protected ToDataSetOutcome toDataSetInternal(ToDataSetOutcome outcome) { + + outcome.putDataSetEntry(TaskViewConstants.FIELD_MERGE_FILTERS, FieldType.BOOLEAN, + this.mergeFilters); + outcome.putDataSetEntry(TaskViewConstants.FIELD_VIEW_SEARCH_TYPE, FieldType.ENUMERATION_MAP, + this.viewSearchType); + outcome.putDataSetEntry(TaskViewConstants.FIELD_HEADERS_MODE, FieldType.MULTICHOICE_MAP, + this.headersMode == null ? new ArrayList<>() : this.headersMode); + outcome.putDataSetEntry(TaskViewConstants.FIELD_HEADERS_DEFAULT_MODE, FieldType.ENUMERATION_MAP, + this.headersDefaultMode); + outcome.putDataSetEntry(TaskViewConstants.FIELD_IS_HEADER_MODE_CHANGEABLE, FieldType.BOOLEAN, + this.isHeaderModeChangeable); + outcome.putDataSetEntry(TaskViewConstants.FIELD_ALLOW_HEADER_TABLE_MODE, FieldType.BOOLEAN, + this.allowHeaderTableMode); + outcome.putDataSetEntry(TaskViewConstants.FIELD_USE_DEFAULT_HEADERS, FieldType.BOOLEAN, + this.useDefaultHeaders); + if (this.defaultHeaders != null) { + outcome.putDataSetEntry(TaskViewConstants.FIELD_DEFAULT_HEADERS, FieldType.STRING_COLLECTION, + this.defaultHeaders); + } + outcome.putDataSetEntry(TaskViewConstants.FIELD_SHOW_MORE_MENU, FieldType.BOOLEAN, + this.showMoreMenu); + if (this.emptyContentText != null) { + outcome.putDataSetEntry(TaskViewConstants.FIELD_EMPTY_CONTENT_TEXT, FieldType.I18N, + this.emptyContentText); + } + outcome.putDataSetEntry(TaskViewConstants.FIELD_EMPTY_CONTENT_ICON, FieldType.TEXT, + this.emptyContentIcon); + + outcome.putDataSetEntry(TaskViewConstants.FIELD_ALL_ALLOWED_NETS, FieldType.BOOLEAN, + this.allAllowedNets); + if (this.allowedNets != null) { + outcome.putDataSetEntry(TaskViewConstants.FIELD_ALLOWED_NETS, FieldType.STRING_COLLECTION, + this.allowedNets); + } + outcome.putDataSetEntry(TaskViewConstants.FIELD_INHERIT_ALLOWED_NETS, FieldType.BOOLEAN, + this.inheritAllowedNets); + + return outcome; + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TaskViewConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TaskViewConstants.java new file mode 100644 index 00000000000..c9acf6f9e54 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/TaskViewConstants.java @@ -0,0 +1,22 @@ +package com.netgrif.application.engine.menu.domain.configurations; + +/** + * Here are declared constants of process task_view_configuration.xml. + */ +public class TaskViewConstants extends ViewConstants { + public static final String FIELD_MERGE_FILTERS = "merge_filters"; + public static final String FIELD_FILTER = "task_filter"; + public static final String FIELD_VIEW_SEARCH_TYPE = "task_view_search_type"; + public static final String FIELD_DEFAULT_HEADERS = "task_default_headers"; + public static final String FIELD_HEADERS_MODE = "task_headers_mode"; + public static final String FIELD_HEADERS_DEFAULT_MODE = "task_headers_default_mode"; + public static final String FIELD_IS_HEADER_MODE_CHANGEABLE = "task_is_header_mode_changeable"; + public static final String FIELD_ALLOW_HEADER_TABLE_MODE = "task_allow_header_table_mode"; + public static final String FIELD_USE_DEFAULT_HEADERS = "use_task_default_headers"; + public static final String FIELD_SHOW_MORE_MENU = "task_show_more_menu"; + public static final String FIELD_EMPTY_CONTENT_TEXT = "task_empty_content_text"; + public static final String FIELD_EMPTY_CONTENT_ICON = "task_empty_content_icon"; + public static final String FIELD_ALL_ALLOWED_NETS = "task_all_allowed_nets"; + public static final String FIELD_ALLOWED_NETS = "task_allowed_nets"; + public static final String FIELD_INHERIT_ALLOWED_NETS = "task_inherit_allowed_nets"; +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewBody.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewBody.java index d636b6e60b1..58c8edf0c0f 100644 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewBody.java +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewBody.java @@ -1,7 +1,7 @@ package com.netgrif.application.engine.menu.domain.configurations; import com.netgrif.application.engine.menu.domain.FilterBody; -import com.netgrif.application.engine.menu.domain.MenuItemView; +import com.netgrif.application.engine.menu.domain.MenuItemViewType; import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; import com.netgrif.application.engine.menu.utils.MenuItemUtils; import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; @@ -23,7 +23,9 @@ public abstract class ViewBody { protected FilterBody filterBody; public abstract ViewBody getAssociatedViewBody(); - public abstract MenuItemView getViewType(); + public abstract MenuItemViewType getViewType(); + public abstract String getFilterFieldId(); + public abstract FieldType getFilterType(); /** * Internal method, that must transform data in concrete class and add them into received outcome. Method must return * the updated outcome. @@ -52,18 +54,17 @@ public String getViewProcessIdentifier() { * @return {@link ToDataSetOutcome} object containing dataSet * */ public ToDataSetOutcome toDataSet() { - return toDataSet(null, null); + return toDataSet(null); }; /** * Transforms data of this class into {@link ToDataSetOutcome}, which contains prepared data for the {@link IDataService#setData} * * @param associatedViewCase case instance of associated view. If provided, caseRef and taskRef are initialized. - * @param filterCase case instance of filter. If provided, caseRef is initialized * * @return {@link ToDataSetOutcome} object containing dataSet * */ - public ToDataSetOutcome toDataSet(Case associatedViewCase, Case filterCase) { + public ToDataSetOutcome toDataSet(Case associatedViewCase) { ToDataSetOutcome outcome = new ToDataSetOutcome(); if (associatedViewCase != null) { @@ -73,9 +74,12 @@ public ToDataSetOutcome toDataSet(Case associatedViewCase, Case filterCase) { List.of(associatedViewCase.getStringId())); String taskId = MenuItemUtils.findTaskIdInCase(associatedViewCase, ViewConstants.TRANS_SETTINGS_ID); outcome.putDataSetEntry(ViewConstants.FIELD_VIEW_CONFIGURATION_FORM, FieldType.TASK_REF, List.of(taskId)); + String allDataTaskId = MenuItemUtils.findTaskIdInCase(associatedViewCase, ViewConstants.TRANS_ALL_MENU_DATA_ID); + outcome.putDataSetEntry(ViewConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM, FieldType.TASK_REF, List.of(allDataTaskId)); } - if (filterCase != null) { - outcome.putDataSetEntry(ViewConstants.FIELD_VIEW_FILTER_CASE, FieldType.CASE_REF, List.of(filterCase.getStringId())); + if (filterBody != null) { + filterBody.setType(getFilterType()); + outcome = filterBody.toDataSet(outcome, getFilterFieldId()); } return toDataSetInternal(outcome); diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewConstants.java b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewConstants.java index 74c38803f06..d27bfa83e03 100644 --- a/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewConstants.java +++ b/src/main/java/com/netgrif/application/engine/menu/domain/configurations/ViewConstants.java @@ -7,10 +7,10 @@ public class ViewConstants { public static final String FIELD_CONFIGURATION_TYPE = "view_configuration_type"; public static final String FIELD_VIEW_CONFIGURATION_ID = "view_configuration_id"; public static final String FIELD_VIEW_CONFIGURATION_FORM = "view_configuration_form"; - public static final String FIELD_VIEW_CONTAINS_FILTER = "contains_filter"; - public static final String FIELD_VIEW_FILTER_CASE = "filter_case"; + public static final String FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM = "view_configuration_all_data_form"; public static final String TRANS_INIT_ID = "initialize"; public static final String TRANS_SETTINGS_ID = "settings"; + public static final String TRANS_ALL_MENU_DATA_ID = "all_menu_data"; public static final String TRANS_SYNC_ID = "data_sync"; } diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/CustomViewTemplate.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/CustomViewTemplate.java new file mode 100644 index 00000000000..ac5970868b7 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/CustomViewTemplate.java @@ -0,0 +1,37 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; + +public class CustomViewTemplate implements Template { + public static final String IDENTIFIER = "custom_view"; + + private static final I18nString NAME = new I18nString("Custom view", + Map.of("sk", "Vlastné zobrazenie", "de", "Benutzerdefinierte Ansicht")); + + private static MenuItemBody buildTemplate() { + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setConfigurationTemplateIdentifier(IDENTIFIER); + menuItemBody.setUseTabbedView(false); + menuItemBody.setUseCustomView(true); + + return menuItemBody; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public I18nString getName() { + return NAME; + } + + @Override + public MenuItemBody getTemplate() { + return buildTemplate(); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/README.md b/src/main/java/com/netgrif/application/engine/menu/domain/templates/README.md new file mode 100644 index 00000000000..7dd8af166fa --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/README.md @@ -0,0 +1,48 @@ +# Menu Item Template Creation Guide + +## Overview + +Templates provide predefined configurations for menu items that can be reused throughout the application. Each template +encapsulates a complete menu item structure with its associated views and filters. + +## Template Structure + +A template must implement the `Template` interface with three core components: + +- **Identifier**: A unique string constant that identifies the template +- **Name**: An internationalized string (I18nString) providing the display name in multiple languages +- **Template Body**: A MenuItemBody instance containing the complete menu item configuration + +## Creation Steps + +1. **Create Template Class** + - Implement the `Template` interface + - Define a unique public static IDENTIFIER constant + - Create a private static I18nString NAME with translations + - Declare a private static MenuItemBody TEMPLATE field + +2. **Build Template Configuration** + - Implement a private static `buildTemplate()` method + - Instantiate MenuItemBody and configure its properties + - Create and configure the appropriate view body (CaseViewBody, TaskViewBody, ...) + - Set up FilterBody for data filtering requirements + - Configure chained views if needed (e.g., TaskViewBody within CaseViewBody) + - Wire all components together through setter methods + +3. **Implement Interface Methods** + - Return IDENTIFIER from `getIdentifier()` + - Return NAME from `getName()` + - Return TEMPLATE from `getTemplate()` + +4. **Register Template** + - Add the template to the `MenuItemTemplateHolder.templates` map + - Use the template's IDENTIFIER as the key + - Instantiate the template class as the value + +## Best Practices + +- Keep identifiers lowercase with underscores for consistency +- Provide translations for all supported languages in the NAME field +- Build template configuration statically to ensure immutability +- Ensure all required view and filter configurations are properly initialized +- Use descriptive identifiers that reflect the template's purpose diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/SimpleCaseViewTemplate.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/SimpleCaseViewTemplate.java new file mode 100644 index 00000000000..59a99ffd44d --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/SimpleCaseViewTemplate.java @@ -0,0 +1,42 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.menu.domain.configurations.CaseViewBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; + +public class SimpleCaseViewTemplate implements Template { + + public static final String IDENTIFIER = "simple_case_view"; + + private static final I18nString NAME = new I18nString("Simple case view", + Map.of("sk", "Zobrazenie prípadov", "de", "Fallansicht")); + + private static MenuItemBody buildTemplate() { + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setConfigurationTemplateIdentifier(IDENTIFIER); + menuItemBody.setUseTabbedView(false); + + CaseViewBody caseViewBody = new CaseViewBody(); + caseViewBody.setFilterBody(Template.defaultCaseFilterBody()); + menuItemBody.setView(caseViewBody); + + return menuItemBody; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public I18nString getName() { + return NAME; + } + + @Override + public MenuItemBody getTemplate() { + return buildTemplate(); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/SimpleTaskViewTemplate.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/SimpleTaskViewTemplate.java new file mode 100644 index 00000000000..e636d1fc466 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/SimpleTaskViewTemplate.java @@ -0,0 +1,42 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.menu.domain.configurations.TaskViewBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; + +public class SimpleTaskViewTemplate implements Template { + + public static final String IDENTIFIER = "simple_task_view"; + + private static final I18nString NAME = new I18nString("Simple task view", + Map.of("sk", "Zobrazenie úloh", "de", "Aufgabenansicht")); + + private static MenuItemBody buildTemplate() { + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setConfigurationTemplateIdentifier(IDENTIFIER); + menuItemBody.setUseTabbedView(false); + + TaskViewBody taskViewBody = new TaskViewBody(); + taskViewBody.setFilterBody(Template.defaultTaskFilterBody()); + menuItemBody.setView(taskViewBody); + + return menuItemBody; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public I18nString getName() { + return NAME; + } + + @Override + public MenuItemBody getTemplate() { + return buildTemplate(); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/SingleTaskViewTemplate.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/SingleTaskViewTemplate.java new file mode 100644 index 00000000000..aa77e986bff --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/SingleTaskViewTemplate.java @@ -0,0 +1,42 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.menu.domain.configurations.SingleTaskViewBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; + +public class SingleTaskViewTemplate implements Template { + + public static final String IDENTIFIER = "single_task_view"; + + private static final I18nString NAME = new I18nString("Single task view", + Map.of("sk", "Zobrazenie jednej úlohy", "de", "Anzeige einer Aufgabe")); + + private static MenuItemBody buildTemplate() { + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setConfigurationTemplateIdentifier(IDENTIFIER); + menuItemBody.setUseTabbedView(false); + + SingleTaskViewBody singleTaskViewBody = new SingleTaskViewBody(); + singleTaskViewBody.setFilterBody(Template.defaultTaskFilterBody()); + menuItemBody.setView(singleTaskViewBody); + + return menuItemBody; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public I18nString getName() { + return NAME; + } + + @Override + public MenuItemBody getTemplate() { + return buildTemplate(); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedCaseViewTemplate.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedCaseViewTemplate.java new file mode 100644 index 00000000000..ecfc1d93f16 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedCaseViewTemplate.java @@ -0,0 +1,45 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.menu.domain.configurations.CaseViewBody; +import com.netgrif.application.engine.menu.domain.configurations.TaskViewBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; + +public class TabbedCaseViewTemplate implements Template { + + public static final String IDENTIFIER = "tabbed_case_view"; + + private static final I18nString NAME = new I18nString("Tabbed case view", + Map.of("sk", "Zobrazenie prípadov v záložkách", "de", "Registerkartenansicht für Fälle")); + + private static MenuItemBody buildTemplate() { + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setConfigurationTemplateIdentifier(IDENTIFIER); + menuItemBody.setUseTabbedView(true); + + CaseViewBody caseViewBody = new CaseViewBody(); + + caseViewBody.setFilterBody(Template.defaultCaseFilterBody()); + caseViewBody.setChainedView(new TaskViewBody()); + menuItemBody.setView(caseViewBody); + + return menuItemBody; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public I18nString getName() { + return NAME; + } + + @Override + public MenuItemBody getTemplate() { + return buildTemplate(); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedTaskViewTemplate.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedTaskViewTemplate.java new file mode 100644 index 00000000000..cc3135c3b27 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedTaskViewTemplate.java @@ -0,0 +1,43 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.menu.domain.configurations.TaskViewBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; + +public class TabbedTaskViewTemplate implements Template { + + public static final String IDENTIFIER = "tabbed_task_view"; + + private static final I18nString NAME = new I18nString("Tabbed task view", + Map.of("sk", "Zobrazenie úloh v záložkách", "de", "Aufgabenansicht in Registerkarten")); + + private static MenuItemBody buildTemplate() { + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setConfigurationTemplateIdentifier(IDENTIFIER); + menuItemBody.setUseTabbedView(true); + + TaskViewBody taskViewBody = new TaskViewBody(); + + taskViewBody.setFilterBody(Template.defaultTaskFilterBody()); + menuItemBody.setView(taskViewBody); + + return menuItemBody; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public I18nString getName() { + return NAME; + } + + @Override + public MenuItemBody getTemplate() { + return buildTemplate(); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedTicketViewTemplate.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedTicketViewTemplate.java new file mode 100644 index 00000000000..4221d963dbf --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/TabbedTicketViewTemplate.java @@ -0,0 +1,46 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.menu.domain.configurations.SingleTaskViewBody; +import com.netgrif.application.engine.menu.domain.configurations.TabbedTicketViewBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; + +public class TabbedTicketViewTemplate implements Template { + + public static final String IDENTIFIER = "tabbed_ticket_view"; + + private static final I18nString NAME = new I18nString("Tabbed ticket view", + Map.of("sk", "Tiketové zobrazenie", "de", "Ticketansicht")); + + private static MenuItemBody buildTemplate() { + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setConfigurationTemplateIdentifier(IDENTIFIER); + menuItemBody.setUseTabbedView(true); + + TabbedTicketViewBody tabbedTicketViewBody = new TabbedTicketViewBody(); + + SingleTaskViewBody singleTaskViewBody = new SingleTaskViewBody(); + singleTaskViewBody.setFilterBody(Template.defaultTaskFilterBody()); + tabbedTicketViewBody.setChainedView(singleTaskViewBody); + menuItemBody.setView(tabbedTicketViewBody); + + return menuItemBody; + } + + @Override + public String getIdentifier() { + return IDENTIFIER; + } + + @Override + public I18nString getName() { + return NAME; + } + + @Override + public MenuItemBody getTemplate() { + return buildTemplate(); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/domain/templates/Template.java b/src/main/java/com/netgrif/application/engine/menu/domain/templates/Template.java new file mode 100644 index 00000000000..2cd42e6b846 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/domain/templates/Template.java @@ -0,0 +1,26 @@ +package com.netgrif.application.engine.menu.domain.templates; + +import com.netgrif.application.engine.menu.domain.FilterBody; +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.petrinet.domain.I18nString; +import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; + +public interface Template { + String getIdentifier(); + I18nString getName(); + MenuItemBody getTemplate(); + + static FilterBody defaultTaskFilterBody() { + FilterBody filterBody = new FilterBody(); + filterBody.setType(FieldType.TASK_FILTER); + filterBody.setQuery("*"); + return filterBody; + } + + static FilterBody defaultCaseFilterBody() { + FilterBody filterBody = new FilterBody(); + filterBody.setType(FieldType.CASE_FILTER); + filterBody.setQuery("*"); + return filterBody; + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java b/src/main/java/com/netgrif/application/engine/menu/service/DashboardItemServiceImpl.java similarity index 97% rename from src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java rename to src/main/java/com/netgrif/application/engine/menu/service/DashboardItemServiceImpl.java index cd8b2c3a09c..20dbb8dbe18 100644 --- a/src/main/java/com/netgrif/application/engine/menu/services/DashboardItemServiceImpl.java +++ b/src/main/java/com/netgrif/application/engine/menu/service/DashboardItemServiceImpl.java @@ -1,4 +1,4 @@ -package com.netgrif.application.engine.menu.services; +package com.netgrif.application.engine.menu.service; import com.netgrif.application.engine.auth.domain.IUser; import com.netgrif.application.engine.auth.domain.LoggedUser; @@ -8,7 +8,7 @@ import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; import com.netgrif.application.engine.menu.domain.dashboard.DashboardItemBody; import com.netgrif.application.engine.menu.domain.dashboard.DashboardItemConstants; -import com.netgrif.application.engine.menu.services.interfaces.DashboardItemService; +import com.netgrif.application.engine.menu.service.interfaces.DashboardItemService; import com.netgrif.application.engine.menu.utils.MenuItemUtils; import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService; diff --git a/src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java b/src/main/java/com/netgrif/application/engine/menu/service/DashboardManagementServiceImpl.java similarity index 98% rename from src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java rename to src/main/java/com/netgrif/application/engine/menu/service/DashboardManagementServiceImpl.java index c35ce0267f8..944270d33e5 100644 --- a/src/main/java/com/netgrif/application/engine/menu/services/DashboardManagementServiceImpl.java +++ b/src/main/java/com/netgrif/application/engine/menu/service/DashboardManagementServiceImpl.java @@ -1,4 +1,4 @@ -package com.netgrif.application.engine.menu.services; +package com.netgrif.application.engine.menu.service; import com.netgrif.application.engine.auth.domain.IUser; import com.netgrif.application.engine.auth.domain.LoggedUser; @@ -9,7 +9,7 @@ import com.netgrif.application.engine.menu.domain.dashboard.DashboardItemConstants; import com.netgrif.application.engine.menu.domain.dashboard.DashboardManagementBody; import com.netgrif.application.engine.menu.domain.dashboard.DashboardManagementConstants; -import com.netgrif.application.engine.menu.services.interfaces.DashboardManagementService; +import com.netgrif.application.engine.menu.service.interfaces.DashboardManagementService; import com.netgrif.application.engine.menu.utils.MenuItemUtils; import com.netgrif.application.engine.petrinet.domain.I18nString; import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; diff --git a/src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java b/src/main/java/com/netgrif/application/engine/menu/service/MenuItemService.java similarity index 63% rename from src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java rename to src/main/java/com/netgrif/application/engine/menu/service/MenuItemService.java index 23f18825609..062dc9f1cbd 100644 --- a/src/main/java/com/netgrif/application/engine/menu/services/MenuItemService.java +++ b/src/main/java/com/netgrif/application/engine/menu/service/MenuItemService.java @@ -1,26 +1,23 @@ -package com.netgrif.application.engine.menu.services; +package com.netgrif.application.engine.menu.service; import com.netgrif.application.engine.auth.domain.IUser; import com.netgrif.application.engine.auth.domain.LoggedUser; import com.netgrif.application.engine.auth.service.interfaces.IUserService; import com.netgrif.application.engine.elastic.service.interfaces.IElasticCaseService; import com.netgrif.application.engine.elastic.web.requestbodies.CaseSearchRequest; -import com.netgrif.application.engine.menu.domain.FilterBody; -import com.netgrif.application.engine.menu.domain.MenuItemBody; -import com.netgrif.application.engine.menu.domain.MenuItemConstants; -import com.netgrif.application.engine.menu.domain.ToDataSetOutcome; +import com.netgrif.application.engine.menu.domain.*; import com.netgrif.application.engine.menu.domain.configurations.ViewBody; import com.netgrif.application.engine.menu.domain.configurations.ViewConstants; -import com.netgrif.application.engine.menu.services.interfaces.IMenuItemService; +import com.netgrif.application.engine.menu.domain.templates.Template; +import com.netgrif.application.engine.menu.service.interfaces.IMenuItemService; import com.netgrif.application.engine.menu.utils.MenuItemUtils; -import com.netgrif.application.engine.petrinet.domain.I18nString; -import com.netgrif.application.engine.petrinet.domain.UriContentType; -import com.netgrif.application.engine.petrinet.domain.UriNode; +import com.netgrif.application.engine.petrinet.domain.*; import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; +import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole; import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; +import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService; +import com.netgrif.application.engine.petrinet.service.interfaces.IProcessRoleService; import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; -import com.netgrif.application.engine.startup.DefaultFiltersRunner; -import com.netgrif.application.engine.startup.FilterRunner; import com.netgrif.application.engine.startup.ImportHelper; import com.netgrif.application.engine.workflow.domain.Case; import com.netgrif.application.engine.workflow.domain.Task; @@ -29,7 +26,13 @@ import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.bson.types.ObjectId; import org.springframework.data.domain.*; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.index.CompoundIndexDefinition; +import org.springframework.data.mongodb.core.index.IndexDefinition; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Service; import java.util.*; @@ -44,47 +47,42 @@ public class MenuItemService implements IMenuItemService { protected final IUserService userService; protected final IUriService uriService; protected final IElasticCaseService elasticCaseService; + protected final MongoTemplate mongoTemplate; + protected final IPetriNetService petriNetService; + protected final IProcessRoleService processRoleService; + + protected Boolean existDatabaseIndexes; protected static final String DEFAULT_FOLDER_ICON = "folder"; + protected static final String GLOBAL_ROLE = "GLOBAL_ROLE"; + protected static final Map CUSTOM_MENU_ITEM_INDEXES = Map.of( + String.format("dataSet.%s.value", MenuItemConstants.FIELD_IDENTIFIER), MenuItemConstants.IDENTIFIER_INDEX_NAME, + String.format("dataSet.%s.value", MenuItemConstants.FIELD_NODE_PATH), MenuItemConstants.NODE_PATH_INDEX_NAME + ); - /** - * Creates new filter case - * - * @param body filter data used for creation - * - * @return initialized filter case instance with the provided data - * */ - @Override - public Case createFilter(FilterBody body) throws TransitionNotExecutableException { - IUser loggedUser = userService.getLoggedOrSystem(); - Case filterCase = createCase(FilterRunner.FILTER_PETRI_NET_IDENTIFIER, body.getTitle().getDefaultValue(), loggedUser.transformToLoggedUser()); - filterCase.setIcon(body.getIcon()); - filterCase = workflowService.save(filterCase); - ToDataSetOutcome dataSetOutcome = body.toDataSet(); - filterCase = setDataWithExecute(filterCase, DefaultFiltersRunner.AUTO_CREATE_TRANSITION, dataSetOutcome.getDataSet()); - log.trace("Created filter case [{}][{}]", filterCase.getStringId(), body.getTitle().getDefaultValue()); - return filterCase; - } /** - * Updates existing filter case + * Ensures custom MongoDB compound indexes for menu items are created on the Case collection. + * Creates background indexes combining processIdentifier with menu item identifier + * and node path fields to optimize menu item queries. * - * @param filterCase filter to be updated - * @param body data values used for update - * - * @return updated filter case instance - * */ + * @see #CUSTOM_MENU_ITEM_INDEXES + */ @Override - public Case updateFilter(Case filterCase, FilterBody body) { - filterCase.setIcon(body.getIcon()); - filterCase = workflowService.save(filterCase); - ToDataSetOutcome dataSetOutcome = body.toDataSet(); - filterCase = setData(filterCase, DefaultFiltersRunner.DETAILS_TRANSITION, dataSetOutcome.getDataSet()); - log.trace("Updated filter case [{}][{}]", filterCase.getStringId(), body.getTitle().getDefaultValue()); - return filterCase; + public void ensureDatabaseIndexes() { + log.info("Ensuring Mongo database menu item indexes"); + CUSTOM_MENU_ITEM_INDEXES.forEach( (indexKey, indexName) -> { + org.bson.Document keys = new org.bson.Document() + .append("processIdentifier", 1) + .append(indexKey, 1); + IndexDefinition index = new CompoundIndexDefinition(keys) + .named(indexName) + .background(); + mongoTemplate.indexOps(Case.class).ensureIndex(index); + }); + existDatabaseIndexes = Boolean.TRUE; } - /** * Creates menu item case and it's configuration cases * @@ -96,12 +94,13 @@ public Case updateFilter(Case filterCase, FilterBody body) { * */ @Override public Case createMenuItem(MenuItemBody body) throws TransitionNotExecutableException { + validateMenuItemBody(body); + log.debug("Creation of menu item case with identifier [{}] started.", body.getIdentifier()); IUser loggedUser = userService.getLoggedOrSystem(); - String sanitizedIdentifier = MenuItemUtils.sanitize(body.getIdentifier()); - if (existsMenuItem(sanitizedIdentifier)) { - throw new IllegalArgumentException(String.format("Menu item identifier %s is not unique!", sanitizedIdentifier)); + if (existsMenuItem(body.getIdentifier())) { + throw new IllegalArgumentException(String.format("Menu item identifier %s is not unique!", body.getIdentifier())); } Case parentItemCase = getOrCreateFolderItem(body.getUri()); @@ -109,47 +108,44 @@ public Case createMenuItem(MenuItemBody body) throws TransitionNotExecutableExce if (newName == null) { newName = new I18nString(body.getIdentifier()); } - Case menuItemCase = createCase(FilterRunner.MENU_NET_IDENTIFIER, newName.getDefaultValue(), + Case menuItemCase = createCase(MenuItemConstants.PROCESS_IDENTIFIER, newName.getDefaultValue(), loggedUser.transformToLoggedUser()); menuItemCase.setUriNodeId(uriService.findByUri(body.getUri()).getStringId()); menuItemCase = workflowService.save(menuItemCase); parentItemCase = appendChildCaseIdAndSave(parentItemCase, menuItemCase.getStringId()); - String nodePath = createNodePath(body.getUri(), sanitizedIdentifier); + String nodePath = createNodePath(body.getUri(), body.getIdentifier()); uriService.getOrCreate(nodePath, UriContentType.CASE); Case viewCase = null; if (body.hasView()) { - viewCase = createView(body.getView()); + viewCase = createView(body.getView(), body.isUseTabbedView()); } ToDataSetOutcome dataSetOutcome = body.toDataSet(parentItemCase.getStringId(), nodePath, viewCase); - menuItemCase = setDataWithExecute(menuItemCase, MenuItemConstants.TRANS_INIT_ID, dataSetOutcome.getDataSet()); + menuItemCase = setDataWithExecute(menuItemCase, MenuItemConstants.TRANS_SYS_INIT_ID, dataSetOutcome.getDataSet()); log.debug("Created menu item case [{}] with identifier [{}].", menuItemCase.getStringId(), body.getIdentifier()); return menuItemCase; } /** - * Updates menu item case and it's configuration cases + * Updates menu item case and it's configuration cases (recreates) * * @param itemCase menu item case to be updated * @param body data used for update * - * @return updated menu item case (configuration cases are updated, but not returned) + * @return recreated menu item case (configuration cases are recreated, but not returned) * */ @Override public Case updateMenuItem(Case itemCase, MenuItemBody body) throws TransitionNotExecutableException { - log.debug("Update of menu item case with identifier [{}] started.", body.getIdentifier()); - String actualUriNodeId = uriService.findByUri(body.getUri()).getStringId(); - if (!itemCase.getUriNodeId().equals(actualUriNodeId)) { - itemCase.setUriNodeId(actualUriNodeId); - itemCase = workflowService.save(itemCase); + validateMenuItemBody(body); + if (itemCase == null) { + throw new IllegalArgumentException("Menu item case is null. Cannot update"); } - Case viewCase = findView(itemCase); - viewCase = handleView(viewCase, body.getView()); - ToDataSetOutcome dataSetOutcome = body.toDataSet(viewCase); - itemCase = setData(itemCase, MenuItemConstants.TRANS_SYNC_ID, dataSetOutcome.getDataSet()); + log.debug("Update of menu item case with identifier [{}] started.", body.getIdentifier()); + workflowService.deleteCase(itemCase); + itemCase = createMenuItem(body); log.debug("Updated menu item case [{}] with identifier [{}].", itemCase.getStringId(), body.getIdentifier()); return itemCase; } @@ -164,6 +160,9 @@ public Case updateMenuItem(Case itemCase, MenuItemBody body) throws TransitionNo * */ @Override public Case createOrUpdateMenuItem(MenuItemBody body) throws TransitionNotExecutableException { + if (body == null) { + throw new IllegalArgumentException("Menu item body cannot be null"); + } Case itemCase = findMenuItem(MenuItemUtils.sanitize(body.getIdentifier())); if (itemCase != null) { return updateMenuItem(itemCase, body); @@ -182,10 +181,14 @@ public Case createOrUpdateMenuItem(MenuItemBody body) throws TransitionNotExecut * */ @Override public Case createOrIgnoreMenuItem(MenuItemBody body) throws TransitionNotExecutableException { - Case itemCase = findMenuItem(body.getIdentifier()); + if (body == null) { + throw new IllegalArgumentException("Menu item body cannot be null"); + } + String sanitizedIdentifier = MenuItemUtils.sanitize(body.getIdentifier()); + Case itemCase = findMenuItem(sanitizedIdentifier); if (itemCase != null) { log.debug("Ignored creation or update of menu item case [{}] with identifier [{}].", itemCase.getStringId(), - body.getIdentifier()); + sanitizedIdentifier); return itemCase; } else { return createMenuItem(body); @@ -201,9 +204,17 @@ public Case createOrIgnoreMenuItem(MenuItemBody body) throws TransitionNotExecut * */ @Override public Case findMenuItem(String identifier) { - String query = String.format("processIdentifier:%s AND dataSet.%s.textValue.keyword:\"%s\"", - FilterRunner.MENU_NET_IDENTIFIER, MenuItemConstants.FIELD_IDENTIFIER, identifier); - return findCase(FilterRunner.MENU_NET_IDENTIFIER, query); + Query query = Query.query( + Criteria.where("processIdentifier").is(MenuItemConstants.PROCESS_IDENTIFIER) + .and(String.format("dataSet.%s.value", MenuItemConstants.FIELD_IDENTIFIER)).is(identifier) + ); + if (existDatabaseIndexes == null || !existDatabaseIndexes) { + ensureDatabaseIndexes(); + } + query.withHint(MenuItemConstants.IDENTIFIER_INDEX_NAME); + List caseAsList = mongoTemplate.find(query, Case.class); + Optional caseOptional = caseAsList.stream().findFirst(); + return caseOptional.map(aCase -> workflowService.findOne(aCase.getStringId())).orElse(null); } /** @@ -218,8 +229,8 @@ public Case findMenuItem(String identifier) { public Case findMenuItem(String uri, String name) { UriNode uriNode = uriService.findByUri(uri); String query = String.format("processIdentifier:%s AND title.keyword:\"%s\" AND uriNodeId:\"%s\"", - FilterRunner.MENU_NET_IDENTIFIER, name, uriNode.getStringId()); - return findCase(FilterRunner.MENU_NET_IDENTIFIER, query); + MenuItemConstants.PROCESS_IDENTIFIER, name, uriNode.getStringId()); + return findCase(MenuItemConstants.PROCESS_IDENTIFIER, query); } /** @@ -231,9 +242,20 @@ public Case findMenuItem(String uri, String name) { * */ @Override public Case findFolderCase(UriNode node) { - String query = String.format("processIdentifier:%s AND dataSet.%s.textValue.keyword:\"%s\"", - FilterRunner.MENU_NET_IDENTIFIER, MenuItemConstants.FIELD_NODE_PATH, node.getUriPath()); - return findCase(FilterRunner.MENU_NET_IDENTIFIER, query); + if (node == null) { + throw new IllegalArgumentException("Node cannot be null"); + } + Query query = Query.query( + Criteria.where("processIdentifier").is(MenuItemConstants.PROCESS_IDENTIFIER) + .and(String.format("dataSet.%s.value", MenuItemConstants.FIELD_NODE_PATH)).is(node.getUriPath()) + ); + if (existDatabaseIndexes == null || !existDatabaseIndexes) { + ensureDatabaseIndexes(); + } + query.withHint(MenuItemConstants.NODE_PATH_INDEX_NAME); + List caseAsList = mongoTemplate.find(query, Case.class); + Optional caseOptional = caseAsList.stream().findFirst(); + return caseOptional.map(aCase -> workflowService.findOne(aCase.getStringId())).orElse(null); } /** @@ -245,9 +267,7 @@ public Case findFolderCase(UriNode node) { * */ @Override public boolean existsMenuItem(String identifier) { - String query = String.format("processIdentifier:%s AND dataSet.%s.textValue.keyword:\"%s\"", - FilterRunner.MENU_NET_IDENTIFIER, MenuItemConstants.FIELD_IDENTIFIER, identifier); - return countCases(FilterRunner.MENU_NET_IDENTIFIER, query) > 0; + return findMenuItem(identifier) != null; } /** @@ -262,20 +282,28 @@ public boolean existsMenuItem(String identifier) { * */ @Override public void moveItem(Case itemCase, String destUri) throws TransitionNotExecutableException { + if (destUri == null) { + throw new IllegalArgumentException("Destination path cannot be null"); + } + if (itemCase == null) { + throw new IllegalArgumentException("Item case cannot be null"); + } log.debug("Move of menu item case [{}] started. Destination path [{}]", itemCase.getStringId(), destUri); if (MenuItemUtils.isCyclicNodePath(itemCase, destUri)) { throw new IllegalArgumentException(String.format("Cyclic path not supported. Destination path: %s", destUri)); } List casesToSave = new ArrayList<>(); - List parentIdList = MenuItemUtils.getCaseIdsFromCaseRef(itemCase, MenuItemConstants.FIELD_PARENT_ID); - if (parentIdList != null && !parentIdList.isEmpty()) { - Case oldParent = removeChildItemFromParent(parentIdList.get(0), itemCase); - casesToSave.add(oldParent); - } + List oldParentIdAsList = MenuItemUtils.getCaseIdsFromCaseRef(itemCase, MenuItemConstants.FIELD_PARENT_ID); UriNode destNode = uriService.getOrCreate(destUri, UriContentType.CASE); Case newParent = getOrCreateFolderItem(destNode.getUriPath()); + + if (oldParentIdAsList != null && !oldParentIdAsList.isEmpty()) { + Case oldParent = removeChildItemFromParent(oldParentIdAsList.get(0), itemCase); + casesToSave.add(oldParent); + } + if (newParent != null) { itemCase.getDataField(MenuItemConstants.FIELD_PARENT_ID).setValue(List.of(newParent.getStringId())); appendChildCaseIdInMemory(newParent, itemCase.getStringId()); @@ -336,7 +364,7 @@ public Case duplicateItem(Case originItem, I18nString newTitle, String newIdenti duplicatedViewCase = duplicateView(originViewCase); } - Case duplicated = createCase(FilterRunner.MENU_NET_IDENTIFIER, newTitle.getDefaultValue(), + Case duplicated = createCase(MenuItemConstants.PROCESS_IDENTIFIER, newTitle.getDefaultValue(), userService.getLoggedOrSystem().transformToLoggedUser()); duplicated.setUriNodeId(originItem.getUriNodeId()); duplicated.setDataSet(originItem.getDataSet()); @@ -365,7 +393,7 @@ public Case duplicateItem(Case originItem, I18nString newTitle, String newIdenti addConfigurationIntoDataSet(duplicatedViewCase, dataSet); } - setDataWithExecute(duplicated, MenuItemConstants.TRANS_INIT_ID, dataSet); + setDataWithExecute(duplicated, MenuItemConstants.TRANS_SYS_INIT_ID, dataSet); List parentIdAsList = MenuItemUtils.getCaseIdsFromCaseRef(originItem, MenuItemConstants.FIELD_PARENT_ID); if (parentIdAsList != null && !parentIdAsList.isEmpty()) { @@ -398,6 +426,137 @@ public Case removeChildItemFromParent(String folderId, Case childItem) { return workflowService.save(parentFolder); } + /** + * Retrieves menu item data groups for the specified case and locale. + * + * @param caseId identifier of the menu item case + * @param locale locale to use for retrieving localized data + * @return list of data groups from the menu item case + */ + @Override + public List getMenuItemData(String caseId, Locale locale) { + Case menuItemCase = workflowService.findOne(caseId); + String taskId = MenuItemUtils.findTaskIdInCase(menuItemCase, MenuItemConstants.TRANS_ALL_MENU_DATA); + return dataService.getDataGroups(taskId, locale).getData(); + } + + /** + * Handles the application of a configuration template to a menu item case. + *

    + * This method retrieves the selected configuration template from the menu item case, + * loads the corresponding template definition, and applies it by creating or updating + * the associated view configuration. If no template is selected, the method returns + * without making any changes. + *

    + * + * @param menuItemCase the menu item case to which the configuration template should be applied + * @return a ConfigurationTemplateOutcome containing the dataSet outcome from applying the template, + * or an empty outcome if no template was selected + * @throws TransitionNotExecutableException if the workflow transition required for applying the template configuration cannot be executed + * @throws IllegalArgumentException if the selected template identifier does not correspond to any registered template + */ + @Override + public ConfigurationTemplateOutcome handleConfigurationTemplate(Case menuItemCase) throws TransitionNotExecutableException { + String selectedTemplate = (String) menuItemCase.getFieldValue(MenuItemConstants.FIELD_CONFIGURATION_TEMPLATES); + if (selectedTemplate == null || selectedTemplate.isEmpty()) { + return new ConfigurationTemplateOutcome(); + } + + String menuItemIdentifier = (String) menuItemCase.getFieldValue(MenuItemConstants.FIELD_IDENTIFIER); + log.debug("Handling configuration template selection for menu item: [{}, {}] and configuration template: {}", + menuItemCase.getStringId(), menuItemIdentifier, selectedTemplate); + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(selectedTemplate); + if (menuItemBodyOpt.isEmpty()) { + throw new IllegalArgumentException(String.format("No configuration template found with name: %s", selectedTemplate)); + } + + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + Case viewCase = null; + if (menuItemBody.hasView()) { + viewCase = createView(menuItemBody.getView(), menuItemBody.isUseTabbedView()); + } + ToDataSetOutcome dataSetOutcome = menuItemBody.toDataSetByConfigTemplate(viewCase); + log.debug("For menu item: [{}. {}] was used configuration template: {}", menuItemCase.getStringId(), + menuItemIdentifier, selectedTemplate); + return new ConfigurationTemplateOutcome(dataSetOutcome); + } + + @Override + public Map collectRoles(List roles) { + // todo rework authorization + Map roleMap = new HashMap<>(); + for (ProcessRole role : roles) { + String key; + I18nString displayName; + + if (role.isGlobal()) { + key = role.getImportId() + ":" + GLOBAL_ROLE; + displayName = new I18nString(role.getName() + " (🌍 Global role)"); + } else { + PetriNet net = petriNetService.get(new ObjectId(role.getNetId())); + key = role.getImportId() + ":" + net.getIdentifier(); + displayName = new I18nString(role.getName() + " (" + net.getTitle() + ")"); + } + + roleMap.put(key, displayName); + } + return roleMap; + } + + @Override + public Map collectRoles(Map roles) { + // todo rework authorization + Map temp = new HashMap<>(); + Map result = new HashMap<>(); + + for (Map.Entry entry : roles.entrySet()) { + if (GLOBAL_ROLE.equals(entry.getValue())) { + Set findGlobalRole = processRoleService.findAllByImportId(ProcessRole.GLOBAL + entry.getKey()); + if (findGlobalRole == null || findGlobalRole.isEmpty()) { + continue; + } + Optional roleOpt = findGlobalRole.stream() + .filter(ProcessRole::isGlobal) + .findFirst(); + if (roleOpt.isEmpty()) { + continue; + } + result.put(roleOpt.get().getImportId() + ":" + GLOBAL_ROLE, + new I18nString(roleOpt.get().getName() + " (🌍 Global role)")); + } else { + if (!temp.containsKey(entry.getValue())) { + temp.put(entry.getValue(), petriNetService.getNewestVersionByIdentifier(entry.getValue())); + } + PetriNet net = temp.get(entry.getValue()); + Optional roleOpt = net.getRoles().values().stream() + .filter(r -> r.getImportId().equals(entry.getKey())) + .findFirst(); + roleOpt.ifPresent(processRole -> result.put(processRole.getImportId() + ":" + net.getIdentifier(), + new I18nString(processRole.getName() + " (" + net.getTitle() + ")"))); + } + } + + return result; + } + + protected void validateMenuItemBody(MenuItemBody body) { + if (body == null) { + throw new IllegalArgumentException("Input data cannot be null"); + } + if (body.getIdentifier() == null) { + throw new IllegalArgumentException("Identifier cannot be null"); + } + if (body.getUri() == null || body.getUri().isBlank()) { + throw new IllegalArgumentException("Uri cannot be null"); + } else { + body.setUri(MenuItemUtils.sanitizeUriSegments(body.getUri(), uriService)); + List uriSegments = List.of(body.getUri().split(uriService.getUriSeparator())); + if (uriSegments.contains(body.getIdentifier())) { + throw new IllegalArgumentException("Uri cannot contain this identifier"); + } + } + } + protected Case findCase(String processIdentifier, String query) { CaseSearchRequest request = CaseSearchRequest.builder() .process(Collections.singletonList(new CaseSearchRequest.PetriNet(processIdentifier))) @@ -409,15 +568,6 @@ protected Case findCase(String processIdentifier, String query) { return resultPage.hasContent() ? resultPage.getContent().get(0) : null; } - protected long countCases(String processIdentifier, String query) { - CaseSearchRequest request = CaseSearchRequest.builder() - .process(Collections.singletonList(new CaseSearchRequest.PetriNet(processIdentifier))) - .query(query) - .build(); - return elasticCaseService.count(List.of(request), userService.getLoggedOrSystem().transformToLoggedUser(), - Locale.getDefault(), false); - } - protected Case duplicateView(Case viewCase) throws TransitionNotExecutableException { Case duplicatedAssociatedViewCase = null; if (MenuItemUtils.hasView(viewCase)) { @@ -436,60 +586,20 @@ protected Case duplicateView(Case viewCase) throws TransitionNotExecutableExcept addConfigurationIntoDataSet(duplicatedAssociatedViewCase, dataSet); } - return setDataWithExecute(duplicatedViewCase, MenuItemConstants.TRANS_INIT_ID, dataSet); + return setDataWithExecute(duplicatedViewCase, ViewConstants.TRANS_INIT_ID, dataSet); } - protected Case findView(Case itemOrViewCase) { - return findCaseInCaseRef(itemOrViewCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); - } - - protected Case findFilter(Case viewCase) { - return findCaseInCaseRef(viewCase, ViewConstants.FIELD_VIEW_FILTER_CASE); - } - - protected Case findCaseInCaseRef(Case useCase, String caseRefId) { - try { - String caseId = MenuItemUtils.getCaseIdFromCaseRef(useCase, caseRefId); - return workflowService.findOne(caseId); - } catch (IllegalArgumentException | NullPointerException ignore) { - return null; - } - } - - protected Case handleView(Case existingViewCase, ViewBody body) throws TransitionNotExecutableException { - if (mustUpdateView(existingViewCase, body)) { - return updateView(existingViewCase, body); - } else if (mustCreateView(existingViewCase, body)) { - return createView(body); - } else if (mustRemoveView(existingViewCase, body)) { - removeView(existingViewCase); - return null; - } else if (mustRemoveAndCreateView(existingViewCase, body)) { - removeView(existingViewCase); - return createView(body); - } else { - return null; - } - } - - protected Case createView(ViewBody body) throws TransitionNotExecutableException { + protected Case createView(ViewBody body, boolean isTabbed) throws TransitionNotExecutableException { IUser loggedUser = userService.getLoggedOrSystem(); Case viewCase = createCase(body.getViewProcessIdentifier(), body.getViewProcessIdentifier(), - loggedUser.transformToLoggedUser()); + loggedUser.transformToLoggedUser(), isTabbed); Case associatedViewCase = null; if (body.hasAssociatedView()) { - associatedViewCase = createView(body.getAssociatedViewBody()); - } - Case filterCase = null; - if (body.getFilterBody() != null) { - if (body.getFilterBody().getFilter() != null) { - filterCase = body.getFilterBody().getFilter(); - } else { - filterCase = createFilter(body.getFilterBody()); - } + associatedViewCase = createView(body.getAssociatedViewBody(), isTabbed); } - ToDataSetOutcome dataSetOutcome = body.toDataSet(associatedViewCase, filterCase); + + ToDataSetOutcome dataSetOutcome = body.toDataSet(associatedViewCase); viewCase = setDataWithExecute(viewCase, ViewConstants.TRANS_INIT_ID, dataSetOutcome.getDataSet()); log.trace("Created configuration view case [{}] of identifier [{}]", viewCase.getStringId(), @@ -497,60 +607,6 @@ protected Case createView(ViewBody body) throws TransitionNotExecutableException return viewCase; } - protected Case updateView(Case viewCase, ViewBody body) throws TransitionNotExecutableException { - Case filterCase = findFilter(viewCase); - filterCase = handleFilter(filterCase, body.getFilterBody()); - - Case associatedViewCase = findView(viewCase); - associatedViewCase = handleView(associatedViewCase, body.getAssociatedViewBody()); - - ToDataSetOutcome outcome = body.toDataSet(associatedViewCase, filterCase); - viewCase = setData(viewCase, ViewConstants.TRANS_SYNC_ID, outcome.getDataSet()); - - log.trace("Updated configuration view case [{}] of identifier [{}]", viewCase.getStringId(), - body.getViewProcessIdentifier()); - return viewCase; - } - - protected void removeView(Case viewCase) { - workflowService.deleteCase(viewCase); - log.trace("Removed configuration view case [{}].", viewCase.getStringId()); - } - - protected Case handleFilter(Case filterCase, FilterBody body) throws TransitionNotExecutableException { - if (mustCreateFilter(filterCase, body)) { - return createFilter(body); - } else if (mustUpdateFilter(filterCase, body)) { - return updateFilter(filterCase, body); - } else { - return filterCase; - } - } - - protected boolean mustUpdateView(Case useCase, ViewBody body) { - return body != null && useCase != null && useCase.getProcessIdentifier().equals(body.getViewProcessIdentifier()); - } - - protected boolean mustRemoveAndCreateView(Case useCase, ViewBody body) { - return body != null && useCase != null && !useCase.getProcessIdentifier().equals(body.getViewProcessIdentifier()); - } - - protected boolean mustRemoveView(Case useCase, ViewBody body) { - return body == null && useCase != null; - } - - protected boolean mustCreateView(Case useCase, ViewBody body) { - return body != null && useCase == null; - } - - protected boolean mustCreateFilter(Case filterCase, FilterBody body) { - return filterCase == null && body != null; - } - - protected boolean mustUpdateFilter(Case filterCase, FilterBody body) { - return filterCase != null && body != null; - } - protected List updateNodeInChildrenFoldersRecursive(Case parentFolder) { List childItemIds = MenuItemUtils.getCaseIdsFromCaseRef(parentFolder, MenuItemConstants.FIELD_CHILD_ITEM_IDS); if (childItemIds == null || childItemIds.isEmpty()) { @@ -575,6 +631,9 @@ protected List updateNodeInChildrenFoldersRecursive(Case parentFolder) { protected void resolveAndHandleNewNodePath(Case folderItem, String destUri) { String newNodePath = resolveNewNodePath(folderItem, destUri); + if (newNodePath.startsWith("//")) { + newNodePath = newNodePath.replace("//", uriService.getUriSeparator()); + } UriNode newNode = uriService.getOrCreate(newNodePath, UriContentType.CASE); folderItem.getDataField(MenuItemConstants.FIELD_NODE_PATH).setValue(newNode.getUriPath()); } @@ -611,7 +670,7 @@ protected Case getOrCreateFolderRecursive(UriNode node, MenuItemBody body, Case return folderCase; } - folderCase = createCase(FilterRunner.MENU_NET_IDENTIFIER, body.getMenuName().getDefaultValue(), + folderCase = createCase(MenuItemConstants.PROCESS_IDENTIFIER, body.getMenuName().getDefaultValue(), loggedUser.transformToLoggedUser()); folderCase.setUriNodeId(node.getParentId()); folderCase = workflowService.save(folderCase); @@ -628,7 +687,7 @@ protected Case getOrCreateFolderRecursive(UriNode node, MenuItemBody body, Case Case parentFolderCase = getOrCreateFolderRecursive(parentNode, body, folderCase); dataSetOutcome.putDataSetEntry(MenuItemConstants.FIELD_PARENT_ID, FieldType.CASE_REF, List.of(parentFolderCase.getStringId())); } - folderCase = setDataWithExecute(folderCase, MenuItemConstants.TRANS_INIT_ID, dataSetOutcome.getDataSet()); + folderCase = setDataWithExecute(folderCase, MenuItemConstants.TRANS_SYS_INIT_ID, dataSetOutcome.getDataSet()); log.trace("Created folder menu item [{}] with identifier [{}]", folderCase.getStringId(), body.getIdentifier()); return folderCase; @@ -671,12 +730,20 @@ protected void addConfigurationIntoDataSet(Case configurationCase, Map> dataSet) { String taskId = MenuItemUtils.findTaskIdInCase(useCase, transId); return setData(taskId, dataSet); diff --git a/src/main/java/com/netgrif/application/engine/menu/service/MenuItemTemplateHolder.java b/src/main/java/com/netgrif/application/engine/menu/service/MenuItemTemplateHolder.java new file mode 100644 index 00000000000..48f27d931ac --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/service/MenuItemTemplateHolder.java @@ -0,0 +1,121 @@ +package com.netgrif.application.engine.menu.service; + +import com.netgrif.application.engine.menu.domain.MenuItemBody; +import com.netgrif.application.engine.menu.domain.templates.*; +import com.netgrif.application.engine.menu.utils.MenuItemUtils; +import com.netgrif.application.engine.petrinet.domain.I18nString; + +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Holder class that manages predefined menu item templates. + *

    + * This class provides a central registry for menu item templates that can be used + * throughout the application. Templates are identified by unique string identifiers + * and can be retrieved or transformed into user-selectable options. + *

    + */ +public class MenuItemTemplateHolder { + /** + * Map of available menu item templates indexed by their unique identifiers. + *

    + * Each entry maps a template identifier to its corresponding Template instance. + * This map is immutable and initialized with predefined templates. + * The key is the template identifier (String), and the value is the Template instance. + *

    + */ + private final static Map templates = Map.of( + TabbedCaseViewTemplate.IDENTIFIER, new TabbedCaseViewTemplate(), + TabbedTaskViewTemplate.IDENTIFIER, new TabbedTaskViewTemplate(), + SimpleCaseViewTemplate.IDENTIFIER, new SimpleCaseViewTemplate(), + SimpleTaskViewTemplate.IDENTIFIER, new SimpleTaskViewTemplate(), + SingleTaskViewTemplate.IDENTIFIER, new SingleTaskViewTemplate(), + TabbedTicketViewTemplate.IDENTIFIER, new TabbedTicketViewTemplate(), + CustomViewTemplate.IDENTIFIER, new CustomViewTemplate() + ); + + + /** + * Retrieves a template by its unique identifier. + *

    + * This method looks up and returns the Template instance associated with the + * provided identifier from the templates registry. + *

    + * + * @param identifier the unique identifier of the template to retrieve + * @return an Optional containing the MenuItemBody instance if found, or empty Optional if no template exists for the given identifier + */ + public static Optional get(String identifier) { + return Optional.ofNullable(templates.get(identifier)).map(Template::getTemplate); + } + + /** + * Retrieves a template by its unique identifier and configures it with the provided URI and menu item identifier. + *

    + * This method looks up the Template instance associated with the provided identifier from the templates registry, + * and then configures the template's body with the specified URI and menu item identifier. + *

    + * + * @param identifier the unique identifier of the template to retrieve + * @param uri the URI to set on the template's body + * @param menuItemIdentifier the menu item identifier to set on the template's body + * @return an Optional containing the configured MenuItemBody instance if found, or empty Optional if no template exists for the given identifier + */ + public static Optional get(String identifier, String uri, String menuItemIdentifier) { + return get(identifier).map(body -> { + body.setUri(uri); + body.setIdentifier(menuItemIdentifier); + return body; + }); + } + + /** + * Retrieves a template by its unique identifier and configures it with the provided URI and menu name. + *

    + * This method looks up the Template instance associated with the provided identifier from the templates registry, + * and then configures the template's body with the specified URI and internationalized menu name. + * The menu item identifier is automatically generated by sanitizing the default menu name value. + * If the default value is null or blank, the first available translation is used instead. + *

    + * + * @param identifier the unique identifier of the template to retrieve + * @param uri the URI to set on the template's body + * @param menuName the internationalized menu name to set on the template's body + * @return an Optional containing the configured MenuItemBody instance if found, or empty Optional if no template exists for the given identifier + * @throws IllegalArgumentException if the menu name has no default value or translations + */ + public static Optional get(String identifier, String uri, I18nString menuName) { + return get(identifier).map(body -> { + body.setUri(uri); + body.setMenuName(menuName); + String defaultName = menuName.getDefaultValue(); + if (defaultName == null || defaultName.isBlank()) { + defaultName = menuName.getTranslations().values().stream() + .findAny() + .orElseThrow(() -> new IllegalArgumentException("Please provide a name for the menu item")); + } + body.setIdentifier(MenuItemUtils.sanitize(defaultName)); + return body; + }); + } + + /** + * Transforms the available templates into a map of selectable options. + *

    + * This method converts the templates map into a format suitable for displaying + * as user-selectable options, where the key is the template identifier and the + * value is the internationalized name of the template. + *

    + * + * @return a map where keys are template identifiers and values are internationalized template names + */ + public static Map transformToOptions() { + return templates.entrySet().stream() + .collect(Collectors.toMap( + Map.Entry::getKey, + entry -> entry.getValue().getName() + )); + } +} diff --git a/src/main/java/com/netgrif/application/engine/menu/services/interfaces/DashboardItemService.java b/src/main/java/com/netgrif/application/engine/menu/service/interfaces/DashboardItemService.java similarity index 88% rename from src/main/java/com/netgrif/application/engine/menu/services/interfaces/DashboardItemService.java rename to src/main/java/com/netgrif/application/engine/menu/service/interfaces/DashboardItemService.java index 6555ad2c04f..3dd698d53c1 100644 --- a/src/main/java/com/netgrif/application/engine/menu/services/interfaces/DashboardItemService.java +++ b/src/main/java/com/netgrif/application/engine/menu/service/interfaces/DashboardItemService.java @@ -1,4 +1,4 @@ -package com.netgrif.application.engine.menu.services.interfaces; +package com.netgrif.application.engine.menu.service.interfaces; import com.netgrif.application.engine.menu.domain.dashboard.DashboardItemBody; import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; diff --git a/src/main/java/com/netgrif/application/engine/menu/services/interfaces/DashboardManagementService.java b/src/main/java/com/netgrif/application/engine/menu/service/interfaces/DashboardManagementService.java similarity index 89% rename from src/main/java/com/netgrif/application/engine/menu/services/interfaces/DashboardManagementService.java rename to src/main/java/com/netgrif/application/engine/menu/service/interfaces/DashboardManagementService.java index 01efb79d055..e5765ddbf3b 100644 --- a/src/main/java/com/netgrif/application/engine/menu/services/interfaces/DashboardManagementService.java +++ b/src/main/java/com/netgrif/application/engine/menu/service/interfaces/DashboardManagementService.java @@ -1,4 +1,4 @@ -package com.netgrif.application.engine.menu.services.interfaces; +package com.netgrif.application.engine.menu.service.interfaces; import com.netgrif.application.engine.menu.domain.dashboard.DashboardManagementBody; import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; diff --git a/src/main/java/com/netgrif/application/engine/menu/services/interfaces/IMenuItemService.java b/src/main/java/com/netgrif/application/engine/menu/service/interfaces/IMenuItemService.java similarity index 64% rename from src/main/java/com/netgrif/application/engine/menu/services/interfaces/IMenuItemService.java rename to src/main/java/com/netgrif/application/engine/menu/service/interfaces/IMenuItemService.java index 9de2a7f2308..4a90a0e1043 100644 --- a/src/main/java/com/netgrif/application/engine/menu/services/interfaces/IMenuItemService.java +++ b/src/main/java/com/netgrif/application/engine/menu/service/interfaces/IMenuItemService.java @@ -1,21 +1,24 @@ -package com.netgrif.application.engine.menu.services.interfaces; +package com.netgrif.application.engine.menu.service.interfaces; -import com.netgrif.application.engine.menu.domain.FilterBody; +import com.netgrif.application.engine.menu.domain.ConfigurationTemplateOutcome; import com.netgrif.application.engine.menu.domain.MenuItemBody; -import com.netgrif.application.engine.menu.domain.MenuItemView; +import com.netgrif.application.engine.menu.domain.MenuItemViewType; +import com.netgrif.application.engine.petrinet.domain.DataGroup; import com.netgrif.application.engine.petrinet.domain.I18nString; import com.netgrif.application.engine.petrinet.domain.UriNode; +import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole; import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; import com.netgrif.application.engine.workflow.domain.Case; import com.netgrif.application.engine.petrinet.domain.dataset.MapOptionsField; +import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.stream.Collectors; public interface IMenuItemService { - Case createFilter(FilterBody body) throws TransitionNotExecutableException; - Case updateFilter(Case filterCase, FilterBody body); + void ensureDatabaseIndexes(); Case createMenuItem(MenuItemBody body) throws TransitionNotExecutableException; Case updateMenuItem(Case itemCase, MenuItemBody body) throws TransitionNotExecutableException; Case createOrUpdateMenuItem(MenuItemBody body) throws TransitionNotExecutableException; @@ -27,6 +30,10 @@ public interface IMenuItemService { void moveItem(Case item, String destUri) throws TransitionNotExecutableException; Case duplicateItem(Case originItem, I18nString newTitle, String newIdentifier) throws TransitionNotExecutableException; Case removeChildItemFromParent(String folderId, Case childItem); + List getMenuItemData(String caseId, Locale locale); + ConfigurationTemplateOutcome handleConfigurationTemplate(Case menuItemCase) throws TransitionNotExecutableException; + Map collectRoles(List roles); + Map collectRoles(Map roles); /** * Gets all tabbed or non-tabbed views @@ -34,21 +41,21 @@ public interface IMenuItemService { * @param isTabbed if true, only tabbed views will be returned * @param isPrimary if true, only views accessible directly from the menu_item will be returned * - * @return All available views defined in {@link MenuItemView} in consideration of input value. Views are returned as + * @return All available views defined in {@link MenuItemViewType} in consideration of input value. Views are returned as * options for {@link MapOptionsField} * */ default Map getAvailableViewsAsOptions(boolean isTabbed, boolean isPrimary) { - return MenuItemView.findAllByIsTabbedAndIsPrimary(isTabbed, isPrimary).stream() - .collect(Collectors.toMap(MenuItemView::getIdentifier, MenuItemView::getName)); + return MenuItemViewType.findAllByIsTabbedAndIsPrimary(isTabbed, isPrimary).stream() + .collect(Collectors.toMap(MenuItemViewType::getIdentifier, MenuItemViewType::getName)); } /** * Gets all tabbed or non-tabbed views * * @param isTabbed if true, only tabbed views will be returned - * @param viewIdentifier identifier of view (defined in {@link MenuItemView}), which is parent to returned views + * @param viewIdentifier identifier of view (defined in {@link MenuItemViewType}), which is parent to returned views * - * @return All available views defined in {@link MenuItemView} in consideration of input values. Views are returned as + * @return All available views defined in {@link MenuItemViewType} in consideration of input values. Views are returned as * options for {@link MapOptionsField} * */ default Map getAvailableViewsAsOptions(boolean isTabbed, String viewIdentifier) { @@ -56,8 +63,8 @@ default Map getAvailableViewsAsOptions(boolean isTabbed, Str if (index > 0) { viewIdentifier = viewIdentifier.substring(0, index); } - return MenuItemView.findAllByIsTabbedAndParentIdentifier(isTabbed, viewIdentifier).stream() - .collect(Collectors.toMap(MenuItemView::getIdentifier, MenuItemView::getName)); + return MenuItemViewType.findAllByIsTabbedAndParentIdentifier(isTabbed, viewIdentifier).stream() + .collect(Collectors.toMap(MenuItemViewType::getIdentifier, MenuItemViewType::getName)); } } diff --git a/src/main/java/com/netgrif/application/engine/menu/utils/MenuItemUtils.java b/src/main/java/com/netgrif/application/engine/menu/utils/MenuItemUtils.java index d1fcaf8e590..b7b3107a8b6 100644 --- a/src/main/java/com/netgrif/application/engine/menu/utils/MenuItemUtils.java +++ b/src/main/java/com/netgrif/application/engine/menu/utils/MenuItemUtils.java @@ -1,9 +1,10 @@ package com.netgrif.application.engine.menu.utils; import com.netgrif.application.engine.menu.domain.MenuItemConstants; +import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; import com.netgrif.application.engine.workflow.domain.Case; import com.netgrif.application.engine.workflow.domain.TaskPair; -import com.netgrif.application.engine.menu.services.interfaces.IMenuItemService; +import com.netgrif.application.engine.menu.service.interfaces.IMenuItemService; import java.text.Normalizer; import java.util.List; @@ -29,6 +30,33 @@ public static String sanitize(String input) { .toLowerCase(); } + /** + * Sanitizes each segment of a URI path by removing diacritical marks, replacing special characters with + * delimiters, and converting to lowercase. The URI is split by the separator defined in the provided + * {@link IUriService}, each segment is sanitized individually, and then the segments are concatenated back + * together. + * + * @param uri the URI string to be sanitized + * @param uriService the service providing the URI separator configuration + * + * @return sanitized URI string with all segments processed, or null if input URI is null + * */ + public static String sanitizeUriSegments(String uri, IUriService uriService) { + if (uri == null) { + return null; + } + String[] uriSegments = uri.split(uriService.getUriSeparator()); + if (uriSegments.length == 0) { + return uriService.getRoot().getUriPath(); + } + StringBuilder sanitizedUriBuilder = new StringBuilder(); + for (String uriSegment : uriSegments) { + sanitizedUriBuilder.append(uriService.getUriSeparator()); + sanitizedUriBuilder.append(MenuItemUtils.sanitize(uriSegment)); + } + return sanitizedUriBuilder.toString().replaceAll("//", uriService.getUriSeparator()); + } + /** * Finds task id in the provided case instance by transition id * @@ -64,7 +92,7 @@ public static String findTaskIdInCase(Case useCase, String transId) { * */ public static boolean isCyclicNodePath(Case folderItem, String destUri) { String oldNodePath = (String) folderItem.getFieldValue(MenuItemConstants.FIELD_NODE_PATH); - return destUri.contains(oldNodePath); + return oldNodePath != null && destUri.contains(oldNodePath); } /** diff --git a/src/main/java/com/netgrif/application/engine/menu/web/MenuController.java b/src/main/java/com/netgrif/application/engine/menu/web/MenuController.java new file mode 100644 index 00000000000..070e5e06615 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/web/MenuController.java @@ -0,0 +1,52 @@ +package com.netgrif.application.engine.menu.web; + +import com.netgrif.application.engine.menu.service.interfaces.IMenuItemService; +import com.netgrif.application.engine.menu.web.responsebodies.MenuItemDataResponse; +import com.netgrif.application.engine.petrinet.domain.DataGroup; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.hateoas.EntityModel; +import org.springframework.hateoas.MediaTypes; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.server.ResponseStatusException; + +import java.util.Base64; +import java.util.List; +import java.util.Locale; + +@Slf4j +@RestController +@Tag(name = "Menu") +@RequiredArgsConstructor +@RequestMapping("/api/menu") +public class MenuController { + + private final IMenuItemService menuItemService; + + // todo menu item authorization + @Operation(summary = "Get relevant data for the menu item", security = {@SecurityRequirement(name = "BasicAuth")}) + @GetMapping(value = "/{encodedCaseId}", produces = MediaTypes.HAL_JSON_VALUE) + public EntityModel getMenuItemData(@PathVariable("encodedCaseId") String encodedCaseId, Locale locale) { + try { + String caseId = new String(Base64.getDecoder().decode(encodedCaseId)); + List dataGroups = menuItemService.getMenuItemData(caseId, locale); + return EntityModel.of(new MenuItemDataResponse(dataGroups)); + } catch (IllegalArgumentException e) { + log.warn("Requested with invalid input", e); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Requested with invalid input"); + } catch (Exception e) { + log.error("Getting menu item data failed", e); + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "Getting menu item data failed"); + } + } + + // todo search with authorization +} + diff --git a/src/main/java/com/netgrif/application/engine/menu/web/responsebodies/MenuItemDataResponse.java b/src/main/java/com/netgrif/application/engine/menu/web/responsebodies/MenuItemDataResponse.java new file mode 100644 index 00000000000..57669493c74 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/menu/web/responsebodies/MenuItemDataResponse.java @@ -0,0 +1,17 @@ +package com.netgrif.application.engine.menu.web.responsebodies; + +import com.netgrif.application.engine.petrinet.domain.DataGroup; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.List; + +@RequiredArgsConstructor +public class MenuItemDataResponse { + + /** + * List of data groups containing menu item data. + */ + @Getter + private final List data; +} diff --git a/src/main/java/com/netgrif/application/engine/workflow/domain/Case.java b/src/main/java/com/netgrif/application/engine/workflow/domain/Case.java index 039f6db8b7d..10e26d1b94b 100644 --- a/src/main/java/com/netgrif/application/engine/workflow/domain/Case.java +++ b/src/main/java/com/netgrif/application/engine/workflow/domain/Case.java @@ -104,7 +104,7 @@ public class Case implements Serializable { @Getter @Setter @Transient - private List immediateData; + private List> immediateData; @Getter @Setter @@ -251,9 +251,6 @@ public void populateDataSet(IInitValueExpressionEvaluator initValueExpressionEva if (field instanceof FieldWithAllowedNets) { this.dataSet.get(key).setAllowedNets(((FieldWithAllowedNets) field).getAllowedNets()); } - if (field instanceof FilterField) { - this.dataSet.get(key).setFilterMetadata(((FilterField) field).getFilterMetadata()); - } if (field instanceof MapOptionsField && ((MapOptionsField) field).isDynamic()) { dynamicOptionsFields.add((MapOptionsField) field); } diff --git a/src/main/java/com/netgrif/application/engine/workflow/domain/DataField.java b/src/main/java/com/netgrif/application/engine/workflow/domain/DataField.java index 5734a9b3e93..5a122c2c2b3 100644 --- a/src/main/java/com/netgrif/application/engine/workflow/domain/DataField.java +++ b/src/main/java/com/netgrif/application/engine/workflow/domain/DataField.java @@ -43,9 +43,6 @@ public class DataField implements Referencable, Serializable { @Getter private List validations; - @Getter - private Map filterMetadata; - @Getter @Setter @JsonIgnore @@ -115,11 +112,6 @@ public void setAllowedNets(List allowedNets) { update(); } - public void setFilterMetadata(Map filterMetadata) { - this.filterMetadata = filterMetadata; - update(); - } - public void setOptions(Map options) { setOptions(options, true); } diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java b/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java index 548ee926a2b..77a6cffdf34 100644 --- a/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java +++ b/src/main/java/com/netgrif/application/engine/workflow/service/DataService.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; +import com.fasterxml.jackson.databind.node.NullNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.netgrif.application.engine.auth.domain.IUser; import com.netgrif.application.engine.auth.service.interfaces.IUserService; @@ -291,12 +292,6 @@ public SetDataEventOutcome setData(Task task, ObjectNode values, Map filterMetadata = parseFilterMetadataValue((ObjectNode) entry.getValue(), fieldType); - if (filterMetadata != null) { - dataField.setFilterMetadata(filterMetadata); - changedField.addAttribute("filterMetadata", filterMetadata); - modified = true; - } Map options = parseOptionsNode(entry.getValue(), fieldType); if (options != null) { setDataFieldOptions(options, dataField, changedField, fieldType); @@ -1010,7 +1005,7 @@ private List parseListLongValues(ObjectNode node) { private List parseAllowedNetsValue(JsonNode jsonNode) { ObjectNode node = (ObjectNode) jsonNode; String fieldType = getFieldTypeFromNode(node); - if (Objects.equals(fieldType, FieldType.CASE_REF.getName()) || Objects.equals(fieldType, FieldType.FILTER.getName())) { + if (Objects.equals(fieldType, FieldType.CASE_REF.getName())) { return parseListStringAllowedNets(node); } return null; @@ -1021,10 +1016,11 @@ private List parseListStringAllowedNets(ObjectNode node) { } private List parseListString(ObjectNode node, String attributeKey) { - ArrayNode arrayNode = (ArrayNode) node.get(attributeKey); - if (arrayNode == null) { + Object objectNode = node.get(attributeKey); + if (objectNode == null || objectNode instanceof NullNode) { return null; } + ArrayNode arrayNode = (ArrayNode) objectNode; ArrayList list = new ArrayList<>(); arrayNode.forEach(string -> list.add(string.asText())); return list; @@ -1053,19 +1049,6 @@ private String getFieldTypeFromNode(ObjectNode node) { return node.get("type").asText(); } - private Map parseFilterMetadataValue(ObjectNode node, String fieldType) { - if (Objects.equals(fieldType, FieldType.FILTER.getName())) { - JsonNode filterMetadata = node.get("filterMetadata"); - if (filterMetadata == null) { - return null; - } - ObjectMapper mapper = new ObjectMapper(); - return mapper.convertValue(filterMetadata, new TypeReference>() { - }); - } - return null; - } - private I18nString parseI18nStringValues(ObjectNode node) { String defaultValue = node.get("defaultValue") != null ? node.get("defaultValue").asText() : ""; Map translations = new HashMap<>(); diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java b/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java deleted file mode 100644 index 75446ea8ed2..00000000000 --- a/src/main/java/com/netgrif/application/engine/workflow/service/FilterImportExportService.java +++ /dev/null @@ -1,380 +0,0 @@ -package com.netgrif.application.engine.workflow.service; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; -import com.google.common.collect.Lists; -import com.netgrif.application.engine.auth.domain.IUser; -import com.netgrif.application.engine.auth.service.interfaces.IUserService; -import com.netgrif.application.engine.configuration.properties.FilterProperties; -import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; -import com.netgrif.application.engine.workflow.domain.filter.FilterImportExport; -import com.netgrif.application.engine.workflow.domain.filter.FilterImportExportList; -import com.netgrif.application.engine.petrinet.domain.I18nString; -import com.netgrif.application.engine.petrinet.domain.PetriNet; -import com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField; -import com.netgrif.application.engine.petrinet.domain.dataset.FileFieldValue; -import com.netgrif.application.engine.petrinet.domain.dataset.logic.FieldBehavior; -import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService; -import com.netgrif.application.engine.startup.DefaultFiltersRunner; -import com.netgrif.application.engine.startup.ImportHelper; -import com.netgrif.application.engine.utils.InputStreamToString; -import com.netgrif.application.engine.workflow.domain.*; -import com.netgrif.application.engine.workflow.service.interfaces.IDataService; -import com.netgrif.application.engine.workflow.service.interfaces.IFilterImportExportService; -import com.netgrif.application.engine.workflow.service.interfaces.ITaskService; -import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.xml.XMLConstants; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; -import java.io.*; -import java.util.*; - -/** - * Service that provides methods for creation of filter export/import cases for users. - * Also provides methods to export and import filters. - */ - -@Service -public class FilterImportExportService implements IFilterImportExportService { - - private static final Logger log = LoggerFactory.getLogger(FilterImportExportService.class); - - private static final String EXPORT_NET_IDENTIFIER = "export_filters"; - private static final String IMPORT_NET_IDENTIFIER = "import_filters"; - private static final String FILTER_NET_IDENTIFIER = "filter"; - - private static final String UPLOAD_FILE_FIELD = "upload_file"; - - private static final String IMPORT_FILTER_TRANSITION = "import_filter"; - - private static final String FIELD_VISIBILITY = "visibility"; - private static final String FIELD_FILTER_TYPE = "filter_type"; - private static final String FIELD_FILTER = "filter"; - private static final String FIELD_NAME = "i18n_filter_name"; - private static final String FIELD_PARENT_CASE_ID = "parent_filter_id"; - private static final String FIELD_PARENT_VIEW_ID = "origin_view_id"; - private static final String FIELD_MISSING_ALLOWED_NETS = "missing_allowed_nets"; - private static final String FIELD_MISSING_NETS_TRANSLATION = "missing_nets_translation"; - - @Autowired - IUserService userService; - - @Autowired - IWorkflowService workflowService; - - @Autowired - IPetriNetService petriNetService; - - @Autowired - DefaultFiltersRunner defaultFiltersRunner; - - @Autowired - private ITaskService taskService; - - @Autowired - private IDataService dataService; - - @Autowired - private FileStorageConfiguration fileStorageConfiguration; - - @Autowired - private FilterProperties filterProperties; - - @Override - public void createFilterImport(IUser author) { - workflowService.createCaseByIdentifier(IMPORT_NET_IDENTIFIER, "Import filters " + author.getFullName(), "", author.transformToLoggedUser()); - } - - @Override - public void createFilterExport(IUser author) { - workflowService.createCaseByIdentifier(EXPORT_NET_IDENTIFIER, "Export filters " + author.getFullName(), "", author.transformToLoggedUser()); - } - - /** - * Method which performs export of selected filters into xml file. - * Method finds all cases by provided ids, transform them into FilterImportExportList object - * and serialize them into xml file on path: storage/filterExport//filters.xml - * - * @param filtersToExport - set of ids of filter cases, which should be exported - * @return FileFieldValue - file field value with path to xml file of exported filters - * @throws IOException - if file which contains exported filters cannot be created - */ - @Override - public FileFieldValue exportFiltersToFile(Collection filtersToExport) throws IOException { - log.info("Exporting selected filters"); - return createXML(exportFilters(filtersToExport)); - } - - /** - * Method which performs export of selected filters into xml file. - * Method finds all cases by provided ids, transform them into FilterImportExportList object - * - * @param filtersToExport - set of ids of filter cases, which should be exported - * @return a serializable wrapper of a list of filter objects in serializable form - */ - @Override - public FilterImportExportList exportFilters(Collection filtersToExport) { - List selectedFilterCases = this.workflowService.findAllById(Lists.newArrayList(filtersToExport)); - FilterImportExportList filterList = new FilterImportExportList(); - - Set exportedFilterIds = new HashSet<>(); - - for (Case exportedFilter : selectedFilterCases) { - LinkedList chain = new LinkedList<>(); - Case currentCase = exportedFilter; - while (true) { - if (exportedFilterIds.contains(currentCase.getStringId())) { - break; - } - exportedFilterIds.add(currentCase.getStringId()); - FilterImportExport currentFilter = createExportClass(currentCase); - chain.push(currentFilter); - if (currentFilter.getParentCaseId() != null) { - currentCase = this.workflowService.findOne(currentFilter.getParentCaseId()); - } else { - break; - } - } - filterList.getFilters().addAll(chain); - } - - return filterList; - } - - /** - * Method which performs import of filters from uploaded xml file. - * Method firstly loads xml file from file field and validates it against xml schema for filters - * export located on path: filter_export_schema.xml - * If the file is correct, method calls performImport method which - * creates filter cases - * - * @return List - list of task ids of imported filter cases in - import_filter transition - * @throws IOException - if imported file is not found - * @throws IllegalFilterFileException - if uploaded xml is not in correct xml format and invalidate against schema - */ - @Override - public List importFilters() throws IOException, IllegalFilterFileException, TransitionNotExecutableException { - log.info("Importing filters"); - FilterImportExportList filterList = loadFromXML(); - return new ArrayList<>(performImport(filterList).values()); - } - - /** - * Method which performs import of filters from already created filter import class instances - * passed in as parameter. - * - * @param filterList - instance of class FilterImportExportList - * @return a mapping of original filter case ids to task ids of imported filter cases in - import_filter transition - * @throws IOException - if imported file is not found - */ - @Override - public Map importFilters(FilterImportExportList filterList) throws IOException, TransitionNotExecutableException { - log.info("Importing filters from imported menu"); - return performImport(filterList); - } - - protected Map performImport(FilterImportExportList filterList) throws IOException, TransitionNotExecutableException { - Map oldToNewFilterId = new HashMap<>(); - Map importedFilterTaskIds = new HashMap<>(); - - if (filterList == null) { - throw new FileNotFoundException(); - } - - filterList.getFilters().forEach(filter -> { - if (filter.getAllowedNets() == null) { - filter.setAllowedNets(new ArrayList<>()); - } - - String parentId = null; - boolean viewOrigin = false; - - if (filter.getParentCaseId() != null && !filter.getParentCaseId().equals("")) { - parentId = oldToNewFilterId.get(filter.getParentCaseId()); - if (parentId == null) { - log.error("Imported filter with ID '" + filter.getCaseId() + "' could not find an imported mapping of its parent case with original ID '" + filter.getParentCaseId() + "'"); - } - } else if (filter.getParentViewId() != null && !filter.getParentViewId().equals("")) { - parentId = filter.getParentViewId(); - viewOrigin = true; - } - - Optional filterCase = defaultFiltersRunner.createFilter( - filter.getFilterName().getDefaultValue(), - filter.getIcon(), - filter.getType(), - filter.getVisibility(), - filter.getFilterValue(), - filter.getAllowedNets(), - filter.getFilterMetadataExport().getMapObject(), - filter.getFilterName().getTranslations(), - filter.getFilterMetadataExport().isDefaultSearchCategories(), - filter.getFilterMetadataExport().isInheritAllowedNets(), - parentId, - viewOrigin, - true - ); - - if (filterCase.isEmpty()) { - return; - } - - oldToNewFilterId.put(filter.getCaseId(), filterCase.get().getStringId()); - - Task importedFilterTask = taskService.searchOne( - QTask.task.transitionId.eq(IMPORT_FILTER_TRANSITION) - .and(QTask.task.caseId.eq(filterCase.get().getStringId())) - ); - importedFilterTaskIds.put(filter.getCaseId(), importedFilterTask.getStringId()); - - // TODO: delete after fixed issue: https://netgrif.atlassian.net/jira/servicedesk/projects/NGSD/issues/ - filterCase.get().getDataSet().get(FIELD_MISSING_ALLOWED_NETS).addBehavior(IMPORT_FILTER_TRANSITION, Collections.singleton(FieldBehavior.HIDDEN)); - filterCase.get().getDataSet().get(FIELD_FILTER).addBehavior(IMPORT_FILTER_TRANSITION, Collections.singleton(FieldBehavior.VISIBLE)); - workflowService.save(filterCase.get()); - }); - taskService.assignTasks(taskService.findAllById(new ArrayList<>(importedFilterTaskIds.values())), userService.getLoggedUser()); - changeFilterField(importedFilterTaskIds.values()); - return importedFilterTaskIds; - } - - /** - * Method which provides reloading of imported filters fields, so if allowed nets are missing, - * htmlTextArea is shown with list of missing allowed nets, otherwise filter preview is shown. - * - * @param filterFields - list of task ids of filters which value should be reloaded - */ - @Override - public void changeFilterField(Collection filterFields) { - filterFields.forEach(f -> { - Task importedFilterTask = taskService.findOne(f); - Case filterCase = workflowService.findOne(importedFilterTask.getCaseId()); - PetriNet filterNet = petriNetService.getNewestVersionByIdentifier(FILTER_NET_IDENTIFIER); - List requiredNets = filterCase.getDataSet().get(FIELD_FILTER).getAllowedNets(); - List currentNets = petriNetService.getExistingPetriNetIdentifiersFromIdentifiersList(requiredNets); - if (currentNets.size() < requiredNets.size()) { - requiredNets.removeAll(currentNets); - StringBuilder htmlTextAreaValue = new StringBuilder( - ((EnumerationMapField) filterNet.getDataSet().get(FIELD_MISSING_NETS_TRANSLATION)).getOptions().get( - LocaleContextHolder.getLocale().getLanguage() - ).getDefaultValue() - ); - htmlTextAreaValue.append("
      "); - requiredNets.forEach(net -> htmlTextAreaValue.append("
    • ").append(net).append("
    • ")); - htmlTextAreaValue.append("
    "); - Map> taskData = new HashMap<>(); - Map missingNets = new HashMap<>(); - missingNets.put("type", "text"); - missingNets.put("value", htmlTextAreaValue.toString()); - taskData.put(FIELD_MISSING_ALLOWED_NETS, missingNets); - this.dataService.setData(importedFilterTask, ImportHelper.populateDataset(taskData)); - filterCase = workflowService.findOne(filterCase.getStringId()); - changeVisibilityByAllowedNets(true, filterCase); - } else { - changeVisibilityByAllowedNets(false, filterCase); - } - workflowService.save(filterCase); - }); - } - - private void changeVisibilityByAllowedNets(boolean allowedNetsMissing, Case filterCase) { - filterCase.getDataSet().get(allowedNetsMissing ? FIELD_MISSING_ALLOWED_NETS : FIELD_FILTER).makeVisible(IMPORT_FILTER_TRANSITION); - filterCase.getDataSet().get(allowedNetsMissing ? FIELD_FILTER : FIELD_MISSING_ALLOWED_NETS).makeHidden(IMPORT_FILTER_TRANSITION); - } - - @Transactional - protected FilterImportExportList loadFromXML() throws IOException, IllegalFilterFileException { - Case exportCase = workflowService.searchOne( - QCase.case$.processIdentifier.eq(IMPORT_NET_IDENTIFIER) - .and(QCase.case$.author.id.eq(userService.getLoggedUser().getStringId())) - ); - - FileFieldValue ffv = (FileFieldValue) exportCase.getDataSet().get(UPLOAD_FILE_FIELD).getValue(); - if (ffv == null) { - throw new FileNotFoundException(); - } - - File f = new File(ffv.getPath()); - validateFilterXML(new FileInputStream(f)); - String importedFilter = InputStreamToString.inputStreamToString(new FileInputStream(f)); - SimpleModule module = new SimpleModule().addDeserializer(Object.class, FilterDeserializer.getInstance()); - XmlMapper xmlMapper = (XmlMapper) new XmlMapper().registerModule(module); - return xmlMapper.readValue(importedFilter, FilterImportExportList.class); - } - - @Transactional - protected FileFieldValue createXML(FilterImportExportList filters) throws IOException { - String filePath = fileStorageConfiguration.getStoragePath() + "/filterExport/" + userService.getLoggedUser().getStringId() + "/" + filterProperties.getFileName(); - File f = new File(filePath); - f.getParentFile().mkdirs(); - - XmlMapper xmlMapper = new XmlMapper(); - xmlMapper.enable(SerializationFeature.INDENT_OUTPUT); - xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true); - xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - xmlMapper.writeValue(baos, filters); - - FileOutputStream fos = new FileOutputStream(f); - baos.writeTo(fos); - - return new FileFieldValue(filterProperties.getFileName(), filePath); - } - - protected FilterImportExport createExportClass(Case filter) { - FilterImportExport exportFilter = new FilterImportExport(); - exportFilter.setCaseId(filter.getStringId()); - exportFilter.setIcon(filter.getIcon()); - - DataField parentCaseId = filter.getDataField(FIELD_PARENT_CASE_ID); - if (parentCaseId.getValue() != null && !parentCaseId.getValue().equals("")) { - exportFilter.setParentCaseId((String) parentCaseId.getValue()); - } - - DataField parentViewId = filter.getDataField(FIELD_PARENT_VIEW_ID); - if (parentViewId.getValue() != null && !parentViewId.getValue().equals("")) { - exportFilter.setParentViewId((String) parentViewId.getValue()); - } - - DataField filterField = filter.getDataField(FIELD_FILTER); - exportFilter.setFilterValue((String) filterField.getValue()); - exportFilter.setAllowedNets(filterField.getAllowedNets()); - exportFilter.setFilterMetadataExport(filterField.getFilterMetadata()); - - DataField visibility = filter.getDataField(FIELD_VISIBILITY); - exportFilter.setVisibility(visibility.getValue().toString()); - - DataField type = filter.getDataField(FIELD_FILTER_TYPE); - exportFilter.setType(type.getValue().toString()); - - DataField name = filter.getDataField(FIELD_NAME); - exportFilter.setFilterName((I18nString) name.getValue()); - - return exportFilter; - } - - private static void validateFilterXML(InputStream xml) throws IllegalFilterFileException { - try { - SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - Schema schema = factory.newSchema(FilterImportExportService.class.getResource("/petriNets/filter_export_schema.xsd")); - Validator validator = schema.newValidator(); - validator.validate(new StreamSource(xml)); - } catch (Exception ex) { - throw new IllegalFilterFileException(ex); - } - } -} - - - diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java b/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java deleted file mode 100644 index 68af8b19387..00000000000 --- a/src/main/java/com/netgrif/application/engine/workflow/service/MenuImportExportService.java +++ /dev/null @@ -1,383 +0,0 @@ -package com.netgrif.application.engine.workflow.service; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.databind.module.SimpleModule; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; -import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator; -import com.netgrif.application.engine.auth.service.interfaces.IUserService; -import com.netgrif.application.engine.files.StorageResolverService; -import com.netgrif.application.engine.petrinet.domain.I18nString; -import com.netgrif.application.engine.petrinet.domain.PetriNet; -import com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField; -import com.netgrif.application.engine.petrinet.domain.dataset.FileField; -import com.netgrif.application.engine.petrinet.domain.dataset.FileFieldValue; -import com.netgrif.application.engine.petrinet.domain.dataset.MultichoiceMapField; -import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole; -import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; -import com.netgrif.application.engine.petrinet.service.interfaces.IPetriNetService; -import com.netgrif.application.engine.startup.DefaultFiltersRunner; -import com.netgrif.application.engine.startup.ImportHelper; -import com.netgrif.application.engine.utils.InputStreamToString; -import com.netgrif.application.engine.workflow.domain.*; -import com.netgrif.application.engine.menu.domain.Menu; -import com.netgrif.application.engine.menu.domain.MenuAndFilters; -import com.netgrif.application.engine.menu.domain.MenuEntry; -import com.netgrif.application.engine.menu.domain.MenuEntryRole; -import com.netgrif.application.engine.workflow.service.interfaces.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import javax.xml.XMLConstants; -import javax.xml.transform.stream.StreamSource; -import javax.xml.validation.Schema; -import javax.xml.validation.SchemaFactory; -import javax.xml.validation.Validator; -import java.io.*; -import java.util.*; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; - -@Service -public class MenuImportExportService implements IMenuImportExportService { - - private static final Logger log = LoggerFactory.getLogger(MenuImportExportService.class); - - private static final String MENU_ITEM_NAME = "entry_name"; - private static final String USE_ICON = "use_icon"; - private static final String ALLOWED_ROLES = "allowed_roles"; - private static final String BANNED_ROLES = "banned_roles"; - private static final String MENU_IDENTIFIER = "menu_identifier"; - private static final String PARENT_ID = "parentId"; - private static final String ENTRY_DEFAULT_NAME = "entry_default_name"; - private static final String GROUP_NAV_TASK = "navigationMenuConfig"; - - @Autowired - IUserService userService; - - @Autowired - IWorkflowService workflowService; - - @Autowired - IPetriNetService petriNetService; - - @Autowired - DefaultFiltersRunner defaultFiltersRunner; - - @Autowired - private ITaskService taskService; - - @Autowired - private IDataService dataService; - - @Autowired - private IFilterImportExportService filterImportExportService; - - @Autowired - private StorageResolverService storageResolverService; - - /** - * Method which performs export of selected menu entries with their filters into xml file. - * Method finds all cases by provided ids, transform them into FilterImportExportList object - * and serialize them into xml file on path: storage/filterExport//filters.xml - * - * @param menusForExport - EnumerationMapField with Ids (delimited by ",") of menu entries as keys - * and identifier of menu they belong to as value - * @param groupId case Id of active group - * @return FileFieldValue - file field value of active group file field used to store exported file - * @throws IOException - if file which contains exported menus cannot be created - */ - @Override - public FileFieldValue exportMenu(EnumerationMapField menusForExport, String groupId, FileField fileField) throws IOException { - log.info("Exporting menu"); - MenuAndFilters menuAndFilters = new MenuAndFilters(); - - for (Map.Entry option : menusForExport.getOptions().entrySet()) { - Menu menu = new Menu(); - menu.setMenuIdentifier(option.getValue().toString()); - - List menuItemCaseIds = Arrays.asList(option.getKey().split(",")); - List filterCaseIds = new ArrayList<>(); - menu.setMenuEntries(new ArrayList<>()); - - menuItemCaseIds.forEach(menuItemCaseId -> { - Case menuItem = workflowService.findOne(menuItemCaseId); - String filterId = ((List) menuItem.getDataSet().get("filter_case").getValue()).get(0); - menu.getMenuEntries().add(createMenuEntryExportClass(menuItem, filterId)); - filterCaseIds.add(filterId); - }); - menuAndFilters.getFilterList().getFilters().addAll(filterImportExportService.exportFilters(filterCaseIds).getFilters()); - - menuAndFilters.getMenuList().getMenus().add(menu); - } - return createXML(menuAndFilters, groupId, fileField); - } - - /** - * Method which performs import of menus from uploaded xml file. - * Method firstly loads xml file from file field and validates it against xml schema for menusWithFilters - * located on path: menu_export_schema.xml. - * Then it calls import of filters provided in uploaded xml file. - * Method then deletes any Preference filter item cases of active group case with same menu identifier - * as any of the menus imported. - * If the file is correct, method creates new instance of Preference filter item cases - * for each menu entry by calling method "createMenuItemCase". - * - * @param menuItemCases - list of Preference filter item cases in active group - * @param ffv - file field from active group case containing uploaded xml file. - * @param parentId - id of active group case - * @return List - list of values delimited by "," containing - * preferenceItem case Id, filter case Id, boolean value determining if Icon should be displayed - * @throws IOException - if imported file is not found - * @throws IllegalMenuFileException - if uploaded xml is not in correct xml format and invalidate against schema - */ - @Override - public List importMenu(List menuItemCases, FileFieldValue ffv, String parentId) throws IOException, IllegalMenuFileException, TransitionNotExecutableException { - StringBuilder resultMessage = new StringBuilder(""); - - List importedEntryAndFilterCaseIds = new ArrayList<>(); - MenuAndFilters menuAndFilters = loadFromXML(ffv); - - //Firstly, remove existing preference_filter_item cases having the same menu identifier as any menu - // which is being currently imported. - List menuItemIdsToReplace = menuItemCases.stream().filter(caze -> menuAndFilters.getMenuList().getMenus().stream() - .anyMatch(menu -> Objects.equals(menu.getMenuIdentifier(), caze.getDataSet().get(MENU_IDENTIFIER).getValue()))) - .map(Case::getStringId).collect(Collectors.toList()); - - //Change remove_option button value to trigger its SET action - if (!menuItemIdsToReplace.isEmpty()) menuItemIdsToReplace.forEach(id -> { - Map> caseToRemoveData = new HashMap<>(); - Map removeBtnData = new HashMap<>(); - removeBtnData.put("type", "button"); - removeBtnData.put("value", "removed"); - caseToRemoveData.put("remove_option", removeBtnData); - - Case caseToRemove = workflowService.findOne(id); - QTask qTask = new QTask("task"); - Task task = taskService.searchOne(qTask.transitionId.eq("view").and(qTask.caseId.eq(caseToRemove.getStringId()))); - dataService.setData(task, ImportHelper.populateDataset(caseToRemoveData)); - }); - - //Import filters - Map importedFilterTaskIds = filterImportExportService.importFilters(menuAndFilters.getFilterList()); - - //Import each menu individually - menuAndFilters.getMenuList().getMenus().forEach(menu -> { - resultMessage.append("\nIMPORTING MENU \"").append(menu.getMenuIdentifier()).append("\":\n"); - menu.getMenuEntries().forEach(menuItem -> { - String entryAndFilterCaseId = createMenuItemCase(resultMessage, menuItem, menu.getMenuIdentifier(), parentId, importedFilterTaskIds.get(menuItem.getFilterCaseId())); - if (!entryAndFilterCaseId.equals("")) importedEntryAndFilterCaseIds.add(entryAndFilterCaseId); - }); - - QTask qTask = new QTask("task"); - Task task = taskService.searchOne(qTask.transitionId.eq(GROUP_NAV_TASK).and(qTask.caseId.eq(parentId))); - - Map> groupData = new HashMap<>(); - Map groupImportResultMessage = new HashMap<>(); - groupImportResultMessage.put("type", "text"); - groupImportResultMessage.put("value", resultMessage.toString()); - groupData.put("import_results", groupImportResultMessage); - dataService.setData(task, ImportHelper.populateDataset(groupData)); - }); - - importedFilterTaskIds.values().forEach(taskId -> { - Task importedFilterTask = taskService.findOne(taskId); - Case filterCase = workflowService.findOne(importedFilterTask.getCaseId()); - try { - taskService.assignTask(importedFilterTask.getStringId()); - taskService.finishTask(importedFilterTask.getStringId()); - workflowService.save(filterCase); - } catch (TransitionNotExecutableException e) { - log.error("Failed to execute \"import_filter\" task with id: " + taskId, e); - } - }); - - return importedEntryAndFilterCaseIds; - } - - /** - * Method which creates new Preference filter item case from imported menuEntry class. - * Before case creation method prepares allowed and banned roles data for the entry while performing checks - * for imported filter and role nets in engine. - * - * @param item - imported MenuEntry item - * @param menuIdentifier - Identifier of new imported menu. - * @param parentId - id of active group case - * @param filterTaskId - task id of imported filter belonging to men item case being created - * @return String - values delimited by "," containing case Id of newly created Preference filter item case, - * Id of its filter case, boolean value determining if Preference filter item case should display icon. - */ - @Override - public String createMenuItemCase(StringBuilder resultMessage, MenuEntry item, String menuIdentifier, String parentId, String filterTaskId) { - AtomicBoolean netCheck = new AtomicBoolean(true); - resultMessage.append("\nMenu entry \"").append(item.getEntryName()).append("\": "); - - Task importedFilterTask = taskService.findOne(filterTaskId); - Case filterCase = workflowService.findOne(importedFilterTask.getCaseId()); - if (filterCase == null) { - resultMessage.append("Filter not found! Menu entry was skipped.\n"); - return ""; - } - - //Creating role entries for allowed_roles/banned_roles datafields - Map allowedRoles = new LinkedHashMap<>(); - Map bannedRoles = new LinkedHashMap<>(); - - //Checks if role nets and imported filters are present in engine and prepares role constrictions data. - if (item.getMenuEntryRoleList() != null && !item.getMenuEntryRoleList().isEmpty()) { - item.getMenuEntryRoleList().forEach(menuEntryRole -> { - String roleImportId = menuEntryRole.getRoleImportId(); - String netImportId = menuEntryRole.getNetImportId(); - if (netImportId != null) { - PetriNet net = petriNetService.getNewestVersionByIdentifier(netImportId); - if (net == null) { - resultMessage.append("\n- Missing net with import ID: \"").append(netImportId).append("\"").append("for role ").append(roleImportId).append("\n"); - netCheck.set(false); - } else { - Optional role = net.getRoles().values().stream().filter(r -> r.getImportId().equals(roleImportId)) - .findFirst(); - if (role.isPresent()) { - //TODO: extend funcionality - add translations to nets and roles - if (menuEntryRole.getAuthorizationType().equals(AuthorizationType.allowed)) { - allowedRoles.put(roleImportId + ":" + netImportId, new I18nString(role.get().getName() + "(" + net.getTitle() + ")")); - } else { - bannedRoles.put(roleImportId + ":" + netImportId, new I18nString(role.get().getName() + "(" + net.getTitle() + ")")); - } - } else { - resultMessage.append("\n- Role with import ID \"").append(roleImportId).append("\" ").append("does not exist in the latest present version of net \"").append(netImportId).append("\"\n"); - netCheck.set(false); - } - } - } - }); - } - //Creating new Case of preference_filter_item net and setting its data... - Case menuItemCase = workflowService.createCase( - petriNetService.getNewestVersionByIdentifier("preference_filter_item").getStringId(), - item.getEntryName() + "_" + menuIdentifier, - "", - userService.getSystem().transformToLoggedUser() - ).getCase(); - - QTask qTask = new QTask("task"); - Task task = taskService.searchOne(qTask.transitionId.eq("init").and(qTask.caseId.eq(menuItemCase.getStringId()))); - try { - taskService.assignTask(task, userService.getLoggedUser()); - menuItemCase.getDataSet().get(MENU_IDENTIFIER).setValue(menuIdentifier); - menuItemCase.getDataSet().get(PARENT_ID).setValue(parentId); - menuItemCase.getDataSet().get(ALLOWED_ROLES).setOptions(allowedRoles); - menuItemCase.getDataSet().get(BANNED_ROLES).setOptions(bannedRoles); - workflowService.save(menuItemCase); - } catch (TransitionNotExecutableException e) { - log.error("Failed to execute \"init\" task on preference filter item case with id: " + menuItemCase.getStringId(), e); - netCheck.set(false); - resultMessage.append("- Failed to execute \"init\" task"); - } - if (netCheck.get()) resultMessage.append("OK\n"); - - return task.getCaseId() + "," + filterCase.getStringId() + "," + item.getUseIcon().toString(); - } - - @Transactional - protected MenuAndFilters loadFromXML(FileFieldValue ffv) throws IOException, IllegalMenuFileException { - File f = new File(ffv.getPath()); - validateFilterXML(new FileInputStream(f)); - SimpleModule module = new SimpleModule().addDeserializer(Object.class, FilterDeserializer.getInstance()); - XmlMapper xmlMapper = (XmlMapper) new XmlMapper().registerModule(module); - String xml = InputStreamToString.inputStreamToString(new FileInputStream(f)); - return xmlMapper.readValue(xml, MenuAndFilters.class); - } - - @Transactional - protected FileFieldValue createXML(MenuAndFilters menuAndFilters, String parentId, FileField fileField) throws IOException { - FileFieldValue ffv = new FileFieldValue(); - try { - ffv.setName("menu_" + userService.getLoggedUser().getFullName().replaceAll("\\s+", "") + ".xml"); - ffv.setPath(storageResolverService.resolve(fileField.getStorageType()).getPath(parentId, fileField.getImportId(), ffv.getName())); - File f = new File(ffv.getPath()); - XmlMapper xmlMapper = new XmlMapper(); - xmlMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY); - xmlMapper.enable(SerializationFeature.INDENT_OUTPUT); - xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - xmlMapper.writeValue(baos, menuAndFilters); - - FileOutputStream fos = new FileOutputStream(f); - baos.writeTo(fos); - } catch (Exception e) { - log.error("Failed to export menu!", e); - } - return ffv; - } - - private MenuEntry createMenuEntryExportClass(Case menuItemCase, String filterCaseId) { - Map allowedRoles = menuItemCase.getDataSet().get(ALLOWED_ROLES).getOptions(); - Map bannedRoles = menuItemCase.getDataSet().get(BANNED_ROLES).getOptions(); - - List menuEntryRoleList = new ArrayList<>(); - - if (allowedRoles != null && !allowedRoles.isEmpty()) { - menuEntryRoleList.addAll(allowedRoles.keySet().stream().map(roleNet -> { - MenuEntryRole newMenuEntryRole = new MenuEntryRole(); - newMenuEntryRole.setRoleImportId(roleNet.split(":")[0]); - newMenuEntryRole.setNetImportId(roleNet.split(":")[1]); - newMenuEntryRole.setAuthorizationType(AuthorizationType.allowed); - return newMenuEntryRole; - }).collect(Collectors.toList())); - } - - if (bannedRoles != null && !bannedRoles.isEmpty()) { - menuEntryRoleList.addAll(bannedRoles.keySet().stream().map(roleNet -> { - MenuEntryRole newMenuEntryRole = new MenuEntryRole(); - newMenuEntryRole.setRoleImportId(roleNet.split(":")[0]); - newMenuEntryRole.setNetImportId(roleNet.split(":")[1]); - newMenuEntryRole.setAuthorizationType(AuthorizationType.banned); - return newMenuEntryRole; - }).collect(Collectors.toList())); - } - - MenuEntry exportMenuItem = new MenuEntry(); - exportMenuItem.setEntryName(menuItemCase.getDataSet().get(MENU_ITEM_NAME).toString()); - exportMenuItem.setFilterCaseId(filterCaseId); - exportMenuItem.setUseIcon((Boolean) menuItemCase.getDataSet().get(USE_ICON).getValue()); - if (!menuEntryRoleList.isEmpty()) exportMenuItem.setMenuEntryRoleList(menuEntryRoleList); - - return exportMenuItem; - } - - @Override - public Map createAvailableEntriesChoices(List menuItemCases) { - Map availableItems; - availableItems = menuItemCases.stream() - .collect(Collectors.toMap(Case::getStringId, v -> new I18nString((String) v.getDataSet().get(ENTRY_DEFAULT_NAME).getValue()))); - - return availableItems; - } - - @Override - public Map addSelectedEntriesToExport(MultichoiceMapField availableEntries, EnumerationMapField menusForExport, String menuIdentifier) { - Map updatedOptions = new LinkedHashMap<>(menusForExport.getOptions()); - String menuCaseIds = ""; - if (availableEntries.getOptions().size() != 0) { - for (String id : availableEntries.getValue()) { - menuCaseIds = menuCaseIds.concat(id + ","); - } - updatedOptions.put(menuCaseIds, new I18nString(menuIdentifier)); - } - return updatedOptions; - } - - private static void validateFilterXML(InputStream xml) throws IllegalMenuFileException { - try { - SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - Schema schema = factory.newSchema(FilterImportExportService.class.getResource("/petriNets/menu_export_schema.xsd")); - Validator validator = schema.newValidator(); - validator.validate(new StreamSource(xml)); - } catch (Exception ex) { - throw new IllegalMenuFileException(ex); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/UserFilterSearchService.java b/src/main/java/com/netgrif/application/engine/workflow/service/UserFilterSearchService.java deleted file mode 100644 index ad133d28856..00000000000 --- a/src/main/java/com/netgrif/application/engine/workflow/service/UserFilterSearchService.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.netgrif.application.engine.workflow.service; - -import com.netgrif.application.engine.auth.service.interfaces.IUserService; -import com.netgrif.application.engine.elastic.service.interfaces.IElasticCaseService; -import com.netgrif.application.engine.elastic.web.requestbodies.CaseSearchRequest; -import com.netgrif.application.engine.startup.FilterRunner; -import com.netgrif.application.engine.workflow.domain.Case; -import com.netgrif.application.engine.workflow.service.interfaces.IUserFilterSearchService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.i18n.LocaleContextHolder; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.stereotype.Service; - -import java.util.Collections; -import java.util.List; - -@Service -public class UserFilterSearchService implements IUserFilterSearchService { - - @Autowired - private IElasticCaseService caseSearchService; - - @Autowired - private IUserService userService; - - @Override - public List autocompleteFindFilters(String userInput) { - Page page = this.caseSearchService.search(Collections.singletonList( - CaseSearchRequest.builder() - .process(Collections.singletonList(new CaseSearchRequest.PetriNet(FilterRunner.FILTER_PETRI_NET_IDENTIFIER))) - .query( - String.format("(title:%s*) AND ((dataSet.visibility.keyValue:private AND authorEmail:%s) OR (dataSet.visibility.keyValue:public))", - userInput, - userService.getLoggedUser().getEmail()) - ) - .transition(Collections.singletonList("view_filter")) - .build() - ), - this.userService.getLoggedOrSystem().transformToLoggedUser(), - PageRequest.of(0, 100), - LocaleContextHolder.getLocale(), - true); - if (page.hasContent()) { - return page.getContent(); - } - return Collections.emptyList(); - } -} diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java b/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java index 87bcb62a025..00e819eb2fe 100644 --- a/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java +++ b/src/main/java/com/netgrif/application/engine/workflow/service/WorkflowService.java @@ -508,11 +508,11 @@ public List getData(String caseId) { } private void setImmediateDataFieldsReadOnly(Case useCase) { - List immediateData = new ArrayList<>(); + List> immediateData = new ArrayList<>(); useCase.getImmediateDataFields().forEach(fieldId -> { try { - Field clone = fieldFactory.buildImmediateField(useCase, fieldId); + Field clone = fieldFactory.buildImmediateField(useCase, fieldId); immediateData.add(clone); } catch (Exception e) { log.error("Could not built immediate field [" + fieldId + "]"); @@ -529,7 +529,7 @@ protected Page setImmediateDataFields(Page cases) { } protected Case setImmediateDataFields(Case useCase) { - List immediateData = new ArrayList<>(); + List> immediateData = new ArrayList<>(); useCase.getImmediateDataFields().forEach(fieldId -> immediateData.add(fieldFactory.buildImmediateField(useCase, fieldId)) diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IFilterImportExportService.java b/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IFilterImportExportService.java deleted file mode 100644 index 6a4cd89ef46..00000000000 --- a/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IFilterImportExportService.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.netgrif.application.engine.workflow.service.interfaces; - -import com.netgrif.application.engine.auth.domain.IUser; -import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; -import com.netgrif.application.engine.workflow.domain.filter.FilterImportExportList; -import com.netgrif.application.engine.petrinet.domain.dataset.FileFieldValue; -import com.netgrif.application.engine.workflow.domain.IllegalFilterFileException; - -import java.io.IOException; -import java.util.Collection; -import java.util.List; -import java.util.Map; - - -/** - * Interface which provides methods for filter import and export. - */ - -public interface IFilterImportExportService { - - FileFieldValue exportFiltersToFile(Collection filtersToExport) throws IOException; - - FilterImportExportList exportFilters(Collection filtersToExport); - - List importFilters() throws IOException, IllegalFilterFileException, TransitionNotExecutableException; - - Map importFilters(FilterImportExportList filters) throws IOException, TransitionNotExecutableException; - - void createFilterImport(IUser author); - - void createFilterExport(IUser author); - - void changeFilterField(Collection filterFields); -} diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IMenuImportExportService.java b/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IMenuImportExportService.java deleted file mode 100644 index fed6dae2275..00000000000 --- a/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IMenuImportExportService.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.netgrif.application.engine.workflow.service.interfaces; - -import com.netgrif.application.engine.petrinet.domain.I18nString; -import com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField; -import com.netgrif.application.engine.petrinet.domain.dataset.FileField; -import com.netgrif.application.engine.petrinet.domain.dataset.FileFieldValue; -import com.netgrif.application.engine.petrinet.domain.dataset.MultichoiceMapField; -import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; -import com.netgrif.application.engine.workflow.domain.Case; -import com.netgrif.application.engine.workflow.domain.IllegalMenuFileException; -import com.netgrif.application.engine.menu.domain.MenuEntry; - -import java.io.IOException; -import java.util.List; -import java.util.Map; - - -/** - * Interface which provides methods for menu import and export. - */ - -public interface IMenuImportExportService { - - Map createAvailableEntriesChoices(List menuItemCases); - - Map addSelectedEntriesToExport(MultichoiceMapField availableEntries, EnumerationMapField menusForExport, String menuidentifier); - - FileFieldValue exportMenu(EnumerationMapField menusForExport, String groupId, FileField fileField) throws IOException; - - List importMenu(List menuItemCases, FileFieldValue ffv, String groupCaseId) throws IOException, IllegalMenuFileException, TransitionNotExecutableException; - - String createMenuItemCase(StringBuilder resultMessage, MenuEntry item, String menuIdentifier, String groupCaseId, String filterCaseId); -} diff --git a/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IUserFilterSearchService.java b/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IUserFilterSearchService.java deleted file mode 100644 index 5689e4c41b0..00000000000 --- a/src/main/java/com/netgrif/application/engine/workflow/service/interfaces/IUserFilterSearchService.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.netgrif.application.engine.workflow.service.interfaces; - -import com.netgrif.application.engine.workflow.domain.Case; - -import java.util.List; - -public interface IUserFilterSearchService { - List autocompleteFindFilters(String userInput); -} diff --git a/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedCaseFilterField.java b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedCaseFilterField.java new file mode 100644 index 00000000000..d63e8d1d946 --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedCaseFilterField.java @@ -0,0 +1,18 @@ +package com.netgrif.application.engine.workflow.web.responsebodies; + +import com.netgrif.application.engine.petrinet.domain.Component; +import com.netgrif.application.engine.petrinet.domain.dataset.CaseFilterField; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Locale; + +@Data +@EqualsAndHashCode(callSuper = true) +public class LocalisedCaseFilterField extends LocalisedField { + + public LocalisedCaseFilterField(CaseFilterField field, Locale locale) { + super(field, locale); + setComponent(new Component("string_query")); + } +} diff --git a/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedFieldFactory.java b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedFieldFactory.java index 34cdb1bfb3a..2244feac92a 100644 --- a/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedFieldFactory.java +++ b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedFieldFactory.java @@ -35,8 +35,12 @@ public static LocalisedField from(Field field, Locale locale) { return fromCase((CaseField) field, locale); } else if (field instanceof FileListField) { return fromFileList((FileListField) field, locale); - } else if (field instanceof FilterField) { - return fromFilter((FilterField) field, locale); + } else if (field instanceof CaseFilterField) { + return fromCaseFilter((CaseFilterField) field, locale); + } else if (field instanceof TaskFilterField) { + return fromTaskFilter((TaskFilterField) field, locale); + } else if (field instanceof ProcessFilterField) { + return fromProcessFilter((ProcessFilterField) field, locale); } else if (field instanceof I18nField) { return fromI18n((I18nField) field, locale); } else { @@ -100,8 +104,16 @@ public static LocalisedField fromFileList(FileListField field, Locale locale) { return new LocalisedFileListField(field, locale); } - public static LocalisedField fromFilter(FilterField field, Locale locale) { - return new LocalisedFilterField(field, locale); + public static LocalisedField fromCaseFilter(CaseFilterField field, Locale locale) { + return new LocalisedCaseFilterField(field, locale); + } + + public static LocalisedField fromTaskFilter(TaskFilterField field, Locale locale) { + return new LocalisedTaskFilterField(field, locale); + } + + public static LocalisedField fromProcessFilter(ProcessFilterField field, Locale locale) { + return new LocalisedProcessFilterField(field, locale); } public static LocalisedField fromI18n(I18nField field, Locale locale) { diff --git a/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedFilterField.java b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedFilterField.java deleted file mode 100644 index 6ce7ede4136..00000000000 --- a/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedFilterField.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.netgrif.application.engine.workflow.web.responsebodies; - -import com.netgrif.application.engine.petrinet.domain.dataset.FilterField; -import lombok.Data; - -import java.util.List; -import java.util.Locale; - -@Data -public class LocalisedFilterField extends LocalisedField { - - private List allowedNets; - private Object filterMetadata; - - public LocalisedFilterField(FilterField field, Locale locale) { - super(field, locale); - this.allowedNets = field.getAllowedNets(); - this.filterMetadata = field.getFilterMetadata(); - } -} diff --git a/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedProcessFilterField.java b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedProcessFilterField.java new file mode 100644 index 00000000000..70886f8caaf --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedProcessFilterField.java @@ -0,0 +1,18 @@ +package com.netgrif.application.engine.workflow.web.responsebodies; + +import com.netgrif.application.engine.petrinet.domain.Component; +import com.netgrif.application.engine.petrinet.domain.dataset.ProcessFilterField; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Locale; + +@Data +@EqualsAndHashCode(callSuper = true) +public class LocalisedProcessFilterField extends LocalisedField { + + public LocalisedProcessFilterField(ProcessFilterField field, Locale locale) { + super(field, locale); + setComponent(new Component("string_query")); + } +} diff --git a/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedTaskFilterField.java b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedTaskFilterField.java new file mode 100644 index 00000000000..1a04a13a75a --- /dev/null +++ b/src/main/java/com/netgrif/application/engine/workflow/web/responsebodies/LocalisedTaskFilterField.java @@ -0,0 +1,18 @@ +package com.netgrif.application.engine.workflow.web.responsebodies; + +import com.netgrif.application.engine.petrinet.domain.Component; +import com.netgrif.application.engine.petrinet.domain.dataset.TaskFilterField; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Locale; + +@Data +@EqualsAndHashCode(callSuper = true) +public class LocalisedTaskFilterField extends LocalisedField { + + public LocalisedTaskFilterField(TaskFilterField field, Locale locale) { + super(field, locale); + setComponent(new Component("string_query")); + } +} diff --git a/src/main/resources/petriNets/engine-processes/export_filters.xml b/src/main/resources/petriNets/engine-processes/export_filters.xml deleted file mode 100644 index 43e332135c5..00000000000 --- a/src/main/resources/petriNets/engine-processes/export_filters.xml +++ /dev/null @@ -1,171 +0,0 @@ - - - export_filters - FTE - Export of filters - file_download - true - false - Export of filters - - - - - - - - exportable_filters - Exportable filters - List of all exportable filters - Select one or more filters to export - - exportable_filters: f.exportable_filters; - - change exportable_filters options { - return findAllFilters() - .collectEntries({filterCase -> [filterCase.stringId, filterCase.title]}) - } - - - - export_btn - Export filters - Export selected filters into xml file - - exportable_filters: f.exportable_filters, - export_file: f.export_file, - trans: t.exportFilter; - - change export_file value { exportFilters(exportable_filters.value) } - change exportable_filters value { [] } - make export_file, visible on trans when {exportable_filters.value.length != 0} - make export_file, hidden on trans when {exportable_filters.value.length == 0} - - - raised - - - - export_file - Exported filters - File with exported filters - Download file with exported filters in xml format - - - - Export filtrov - Exportovateľné filtre - Zoznam všetkých exportovateľných filtrov - Vyberte jeden alebo viac filtrov na export - Exportovať filtre - Export vybraných filtrov do súboru xml - Exportované filtre - Súbor s exportovanými filtrami - Stiahnutie súboru s exportovanými filtrami vo formáte xml - - - Exportieren von Filtern - Exportierbare Filter - Liste aller exportierbaren Filter - Wählen Sie einen oder mehrere Filter für den Export - Filter exportieren - Ausgewählte Filter in xml-Datei exportieren - Exportierte Filter - Datei mit exportierten Filtern - Datei mit exportierten Filtern im xml-Format herunterladen - - - - exportFilter - 200 - 100 - - 0 - - auto - - - DataGroup_0 - grid - - exportable_filters - - editable - - - 0 - 0 - 1 - 2 - 0 - - outline - - - - export_btn - - editable - - - 2 - 0 - 1 - 2 - 0 - - outline - - - - export_file - - hidden - - - 0 - 1 - 1 - 2 - 0 - - outline - - - - - - - export_file: f.export_file, - trans: t.exportFilter; - - make export_file, hidden on trans when {true} - - - - - - - p1 - 100 - 100 - - 1 - false - - - - a1 - regular - p1 - exportFilter - 1 - - - a2 - regular - exportFilter - p1 - 1 - - diff --git a/src/main/resources/petriNets/engine-processes/filter.xml b/src/main/resources/petriNets/engine-processes/filter.xml deleted file mode 100644 index 4563e2d4c5e..00000000000 --- a/src/main/resources/petriNets/engine-processes/filter.xml +++ /dev/null @@ -1,1094 +0,0 @@ - - - filter - FTR - Filter - filter_alt - true - false - New filter - - - - create - - - caseId: f.filter_case_id; - - change caseId value {return useCase.stringId}; - - - - - - - - system - System - - - - - - { - com.netgrif.application.engine.petrinet.domain.dataset.TaskField myFullFilter - -> - change myFullFilter value {return [findTask({it.caseId.eq(useCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId]} - } - - - - filter - Filter - - - filter_type - Filter type - - - - - - - visibility - Filter visibility - - - - - public - - - origin_view_id - Origin ViewId - - set - - - origin_view_id: f.origin_view_id, - and_view: f.and_view, - trimmed_origin_view_id: f.trimmed_origin_view_id, - t1: t.view_filter, - t2: t.view_as_ancestor; - - if (origin_view_id.value == "") { - return; - } - - // the same regex is used in the frontend FilterExtractionService. Please keep them in sync - def match = origin_view_id.value =~ "^.*?(-\\d+)?\$" - match.matches() - - def trimmed_id; - - if (match.start(1) == -1) { - trimmed_id = origin_view_id.value - } else { - trimmed_id = origin_view_id.value.substring(0, match.start(1)) - } - - change trimmed_origin_view_id value {trimmed_id} - make and_view, visible on t1 when {true} - make and_view, visible on t2 when {true} - make trimmed_origin_view_id, visible on t1 when {true} - make trimmed_origin_view_id, visible on t2 when {true} - make origin_view_id, hidden on t1 when {true} - make origin_view_id, hidden on t2 when {true} - - - - - - parent_filter_id - parent filter ID - - set - - - parent_filter_id: f.parent_filter_id, - ancestor_task_ref: f.taskref_and_parent; - - def ancestor_view_filter = findTask({it.caseId.eq(parent_filter_id.value).and(it.task.transitionId.eq("view_as_ancestor"))}) - - change ancestor_task_ref value {[ancestor_view_filter.stringId]} - - - - - - new_title - Filter name - - - i18n_filter_name - - - - filter_case_id - - - - menu_identifier - - - - and_me - AND - - - and_view - AND - - - taskref_and_parent - - - - trimmed_origin_view_id - Filter from view with ID - - - is_imported - imported - 0 - - isNotImported: f.is_not_imported; - - change isNotImported value { return 0 } - - - - is_not_imported - not imported - 1 - - - missing_allowed_nets - Missing processes - List of missing processes for current filter - - htmltextarea - - - - missing_nets_translation - - - - - - - - - my_full_filter - - - - allowed_nets - Allowed nets - - - - Filter - Nový Filter - Filter - Druh filtra - Filter prípadov - Filter úloh - Viditeľnosť filtra - Verejný - Súkromný - ViewId pôvodu - Názov filtra - Vytvoriť nový filter - Podrobnosti - Uložiť - A SÚČASNE - Filter z obrazovky s ID - Názov prípadu - Importovať filter - Chýbajúce procesy - Zoznam chýbajúcich procesov pre aktuálny filter - ID rodičovského filtra - Povolené siete - - - Filter - Neuer Filter - Filter - Filtertyp - Fallfilter - Aufgabenfilter - Filter Sichtbarkeit - Öffentlich - Persönlich - Herkunft ViewId - Filtername - Neuer Filter erstellen - Details - Speichern - UND - Filter von der Ansicht mit der ID - Fallname - Importfilter - Fehlende Prozesse - Liste der fehlenden Prozesse für den aktuellen Filter - Elternfilter-ID - Erlaubte Netze - - - - newFilter - 620 - 260 - - - 0 - - auto - - myFilter - grid - - my_full_filter - - visible - - - 0 - 0 - 1 - 4 - 0 - - - - - DataGroup_0 - grid - - visibility - - editable - required - - - 0 - 1 - 1 - 4 - 0 - - outline - - - - new_title - - editable - required - - userTitle: f.new_title, - i18nName: f.i18n_filter_name; - - change i18nName value { new com.netgrif.application.engine.petrinet.domain.I18nString(userTitle.value) } - - - - 0 - 2 - 1 - 4 - 0 - - outline - - - - allowed_nets - - editable - - - 0 - 3 - 1 - 4 - 0 - - outline - - - - - - Save - - - name: f.new_title; - useCase.setTitle(name.value) - workflowService.save(useCase) - - - - - - t2 - 740 - 380 - - 0 - - - - DataGroup_0 - grid - - filter_type - - visible - - - 0 - 0 - 1 - 1 - 0 - - outline - - - - visibility - - visible - - - 1 - 0 - 1 - 1 - 0 - - outline - - - - - myFilter - grid - - my_full_filter - - visible - - - 0 - 0 - 1 - 4 - 0 - - - - - - frontend_create - 380 - 260 - - - 0 - - - DataGroup_0 - grid - - filter - - editable - - - 0 - 0 - 1 - 4 - 0 - - outline - - - - filter_type - - editable - - - 0 - 1 - 1 - 4 - 0 - - outline - - - - origin_view_id - - editable - - - 0 - 2 - 1 - 4 - 0 - - outline - - - - parent_filter_id - - editable - - - 0 - 3 - 1 - 4 - 0 - - outline - - - - allowed_nets - - editable - - - 0 - 4 - 1 - 4 - 0 - - outline - - - - - finish - - - taskRef: f.my_full_filter; - - initializeMyFullFilterTaskRef(taskRef) - - - - - - auto_create - 500 - 180 - - - 0 - - - DataGroup_0 - grid - - filter - - editable - - - 0 - 0 - 1 - 1 - 0 - - outline - - - - filter_type - - editable - - - 1 - 0 - 1 - 1 - 0 - - outline - - - - visibility - - editable - - - 2 - 0 - 1 - 1 - 0 - - outline - - - - origin_view_id - - editable - - - 3 - 0 - 1 - 1 - 0 - - outline - - - - parent_filter_id - - editable - - - 0 - 1 - 1 - 1 - 0 - - outline - - - - - finish - - - taskRef: f.my_full_filter; - - initializeMyFullFilterTaskRef(taskRef) - - - - - - view_filter - 550 - 420 - - - 0 - - - system - - true - - - - DataGroup_0 - grid - - filter - - visible - - - 0 - 0 - 1 - 4 - 0 - - outline - - - - filter_case_id - - hidden - - - 0 - 1 - 1 - 4 - 0 - - outline - - - - origin_view_id - - forbidden - - - 0 - 2 - 1 - 4 - 0 - - outline - - - - taskref_and_parent - - visible - - - 0 - 3 - 1 - 4 - 0 - - outline - - - - new_title - - hidden - - name: f.new_title, - i18nName: f.i18n_filter_name; - - change i18nName value { new com.netgrif.application.engine.petrinet.domain.I18nString(name.value) } - - - - 0 - 4 - 1 - 4 - 0 - - outline - - - - - DataGroup_1 - grid - - and_view - - forbidden - - - 0 - 0 - 1 - 1 - 0 - - outline - - - - trimmed_origin_view_id - - forbidden - - - 1 - 0 - 1 - 3 - 0 - - outline - - - - - - view_as_ancestor - 451 - 418 - - - 0 - - - system - - true - - - - DataGroup_0 - grid - - and_me - - visible - - - 0 - 0 - 1 - 1 - 0 - - outline - - - - filter - - visible - - - 1 - 0 - 1 - 3 - 0 - - outline - - - - taskref_and_parent - - visible - - - 0 - 3 - 1 - 4 - 0 - - outline - - - - - DataGroup_1 - grid - - and_view - - forbidden - - - 0 - 0 - 1 - 1 - 0 - - outline - - - - trimmed_origin_view_id - - forbidden - - - 1 - 0 - 1 - 3 - 0 - - outline - - - - origin_view_id - - forbidden - - - 0 - 3 - 1 - 3 - 0 - - outline - - - - - - import_filter - 740 - 180 - - - 0 - - - DataGroup_0 - grid - - - new_title - - editable - - name: f.new_title; - - change name value { useCase.getTitle() } - - - name: f.new_title, - i18nName: f.i18n_filter_name; - - change i18nName value { new com.netgrif.application.engine.petrinet.domain.I18nString(name.value) } - - - - 0 - 0 - 1 - 1 - 0 - - outline - - - - filter_type - - visible - - - 1 - 0 - 1 - 1 - 0 - - outline - - - - visibility - - editable - - - 2 - 0 - 1 - 1 - 0 - - outline - - - - missing_allowed_nets - - hidden - - - 0 - 2 - 1 - 2 - 0 - - outline - - - - - DataGroup_1 - grid - - my_full_filter - - visible - - - 0 - 0 - 1 - 4 - 0 - - outline - - - - - - - - name: f.new_title; - changeCaseProperty "title" about { name.value } - - - - - - - - p1 - 260 - 260 - - 1 - false - - - p2 - 740 - 260 - - 0 - false - - - p3 - 540 - 260 - - 0 - false - - - p4 - 660 - 140 - - 0 - false - - - p5 - 500 - 340 - - 0 - false - - - - a3 - regular - p1 - frontend_create - 1 - - - a4 - regular - frontend_create - p3 - 1 - - - a5 - regular - p3 - newFilter - 1 - - - a6 - regular - newFilter - p2 - 1 - - - a7 - read - p2 - t2 - 1 - - - a8 - regular - p1 - auto_create - 1 - - - a9 - regular - auto_create - p2 - 1 - is_not_imported - - - a12 - regular - import_filter - p2 - 1 - - - a13 - regular - auto_create - p4 - 0 - is_imported - - - a14 - regular - p4 - import_filter - 1 - - - a15 - regular - frontend_create - p5 - 1 - - - a18 - read - p5 - view_as_ancestor - 1 - - - a19 - read - p5 - view_filter - 1 - - - a20 - regular - auto_create - p5 - 1 - - diff --git a/src/main/resources/petriNets/engine-processes/import_filters.xml b/src/main/resources/petriNets/engine-processes/import_filters.xml deleted file mode 100644 index af74e2c35f9..00000000000 --- a/src/main/resources/petriNets/engine-processes/import_filters.xml +++ /dev/null @@ -1,182 +0,0 @@ - - - import_filters - FTI - Import of filters - file_upload - true - false - Import of filters - - - - - - - - upload_file - Upload filter file - Insert file containing filters - Insert xml file that contains filters - - importedFilters: f.imported_filters; - - taskService.findAllById(importedFilters.value).forEach({filterTask -> - workflowService.deleteCase(filterTask.caseId) - }) - change importedFilters value { return [] } - - - - import_file - - Import filters - Import filters from uploaded xml file - - raised - - - - imported_filters - - - importedFilters: f.imported_filters; - - filterImportExportService.changeFilterField(importedFilters.value) - - - - - Import filtrov - Nahratie súboru s filtrami - Vložete súbor obsahujúci filtre - Vložte xml súbor, ktorý obsahuje filtre - Importovať filtre - Importovať filtre z nahraného xml súboru - - - Import von Filtern - Filterdatei hochladen - Datei mit Filtern einfügen - Xml-Datei einfügen, die Filter enthält - Filter importieren - Filter aus hochgeladener xml-Datei importieren - - - - importFilter - 200 - 100 - - - 0 - - auto - - DataGroup_0 - grid - - upload_file - - editable - - - 0 - 0 - 1 - 2 - 0 - - outline - - - - import_file - - editable - - importedFiltersRef: f.imported_filters; - - change importedFiltersRef value { importFilters() } - - - - 2 - 0 - 1 - 2 - 0 - - outline - - - - - DataGroup_1 - grid - - imported_filters - - editable - - - 0 - 1 - 1 - 4 - 0 - - outline - - - - - - - - importedFilters: f.imported_filters; - - taskService.finishTasks(taskService.findAllById(importedFilters.value), userService.getLoggedUser()) - change importedFilters value { [] } - - - - - - - - importedFilters: f.imported_filters; - - taskService.findAllById(importedFilters.value).forEach({filterTask -> - workflowService.deleteCase(filterTask.caseId) - }) - change importedFilters value { [] } - - - - - - - p1 - 100 - 100 - - 1 - false - - - - a1 - regular - p1 - importFilter - 1 - - - a2 - regular - importFilter - p1 - 1 - - diff --git a/src/main/resources/petriNets/engine-processes/menu/tabbed_case_view_configuration.xml b/src/main/resources/petriNets/engine-processes/menu/case_view_configuration.xml similarity index 52% rename from src/main/resources/petriNets/engine-processes/menu/tabbed_case_view_configuration.xml rename to src/main/resources/petriNets/engine-processes/menu/case_view_configuration.xml index d1c28db279c..bd7228d7f41 100644 --- a/src/main/resources/petriNets/engine-processes/menu/tabbed_case_view_configuration.xml +++ b/src/main/resources/petriNets/engine-processes/menu/case_view_configuration.xml @@ -1,7 +1,7 @@ - tabbed_case_view_configuration - TCV - Tabbed case view configuration + case_view_configuration + CVC + Case view configuration check_box_outline_blank true false @@ -25,16 +25,23 @@ default - false - false true + + view_create + + + is_tabbed_var_arc: f.is_tabbed_var_arc; + change is_tabbed_var_arc value { Boolean.valueOf(params["is_tabbed"]) ? 1 : 0 } + + + view_delete - + removeViewCase() @@ -49,30 +56,17 @@ Admin - - { - com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField filterAutocomplete, - com.netgrif.application.engine.petrinet.domain.dataset.TaskField previewTaskRef, - com.netgrif.application.engine.petrinet.domain.dataset.CaseField selectedFilterRef, - com.netgrif.application.engine.petrinet.domain.dataset.ButtonField updateBtn, - com.netgrif.application.engine.petrinet.domain.Transition trans - -> - if (filterAutocomplete.getOptions().containsKey(filterAutocomplete.value)) { - change previewTaskRef value { - return [findTask({it.caseId.eq(filterAutocomplete.value).and(it.transitionId.eq("view_filter"))}).stringId] - } - make updateBtn,editable on trans when { true } - } else { - change filterAutocomplete options { - def findAllPredicate = { filterCase -> !selectedFilterRef.value.contains(filterCase.stringId) - && filterCase.dataSet["filter_type"].value == "Case" } - return findFilters(filterAutocomplete.value != null ? filterAutocomplete.value : "") - .findAll(findAllPredicate) - .collectEntries({filterCase -> [filterCase.stringId, filterCase.title]}) - } - change previewTaskRef value { [] } - make updateBtn,visible on trans when { true } - } + + { -> + def advancedContentFormField = useCase.getField("advanced_content_form") + def taskIds = [useCase.tasks.find { taskPair -> taskPair.transition == "header_settings"}.task, + useCase.tasks.find { taskPair -> taskPair.transition == "create_case_btn_settings"}.task, + useCase.tasks.find { taskPair -> taskPair.transition == "filter_settings"}.task] + String nextViewTaskId = useCase.tasks.find { taskPair -> taskPair.transition == "open_case_settings"}?.task + if (nextViewTaskId != null) { + taskIds.add(nextViewTaskId) + } + change advancedContentFormField value { taskIds } } @@ -114,114 +108,10 @@ } - - - selected_filter_preview - - </data> - <data type="taskRef"> - <id>current_filter_preview</id> - <title/> - </data> - <data type="i18n"> - <id>filter_header</id> - <title/> - <init name="filter_header">Current filter</init> - <component> - <name>divider</name> - </component> - </data> - <data type="text"> - <id>new_filter_id</id> - <title/> - </data> - <data type="boolean" immediate="true"> - <id>contains_filter</id> - <title/> - <init>false</init> - </data> - <data type="enumeration_map"> - <id>filter_autocomplete_selection</id> - <title name="filter_autocomplete_selection">Select new filter - - autocomplete_dynamic - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - - update_filter - - <placeholder name="update_filter">Update view with selected filter</placeholder> - <component> - <name>raised</name> - </component> - <action trigger="set"> - trans: t.settings, - update_filter: f.update_filter, - contains_filter: f.contains_filter, - filter_case: f.filter_case, - filterAutocomplete: f.filter_autocomplete_selection; - - boolean containsFilter = filterAutocomplete.value != null && filterAutocomplete.value != "" - if (containsFilter) { - def filterCase = findCase({it._id.eq(filterAutocomplete.value)}) - if (filterCase.dataSet["filter_type"].value != "Case") { - throw new IllegalArgumentException("Filter is of wrong type. Only filter of Case type allowed.") - } - } - - change contains_filter value { containsFilter } - change filter_case value { [filterAutocomplete.value] } - change filterAutocomplete value { "" } - make update_filter,visible on trans when { true } - </action> - </data> - <data type="caseRef"> - <id>filter_case</id> - <title/> - <action trigger="set"> - filterTaskRef: f.current_filter_preview, - contains_filter: f.contains_filter, - filterCaseRef: f.filter_case; - - if (filterCaseRef.value == null || filterCaseRef.value == []) { - change filterTaskRef value { [] } - change contains_filter value { false } - return - } - - def filterCase = findCase({it._id.eq(filterCaseRef.value[0])}) - change filterTaskRef value { - return [findTask({it.caseId.eq(filterCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId] - } - change contains_filter value { true } - </action> - <allowedNets> - <allowedNet>filter</allowedNet> - </allowedNets> - </data> - <!-- VIEW CONFIGURATION DATA --> <data type="enumeration_map" immediate="true"> - <id>view_search_type</id> - <title name="view_search_type">Search type for case view + case_view_search_type + Search type for case view @@ -229,7 +119,7 @@ fulltext_advanced - + create_case_button_title "New case" button title @@ -292,18 +182,18 @@ - show_more_menu - Show more menu for case item? + case_show_more_menu + Show more menu for case item? false - allow_header_table_mode - Allow table mode for headers? + case_allow_header_table_mode + Allow table mode for headers? true - headers_mode - Header mode + case_headers_mode + Header mode @@ -311,23 +201,23 @@ sort,edit,search - headersMode: f.headers_mode, - defaultMode: f.headers_default_mode, + headersMode: f.case_headers_mode, + defaultMode: f.case_headers_default_mode, holder: f.headers_options_holder; updateOptionsBasedOnValue(defaultMode, headersMode, holder) - headersMode: f.headers_mode, - defaultMode: f.headers_default_mode, + headersMode: f.case_headers_mode, + defaultMode: f.case_headers_default_mode, holder: f.headers_options_holder; updateOptionsBasedOnValue(defaultMode, headersMode, holder) - headers_default_mode - Default header mode + case_headers_default_mode + Default header mode @@ -345,8 +235,8 @@ - is_header_mode_changeable - Can header mode be changed? + case_is_header_mode_changeable + Can header mode be changed? true @@ -354,22 +244,14 @@ Use custom default headers? true - - default_headers - Set default headers - Example: "meta-title,meta-visualId" - - defaultHeaders: f.this; - - String trimmed = defaultHeaders.value?.replaceAll("\\s","") - if (defaultHeaders.value != trimmed) { - change defaultHeaders value { trimmed } - } - + + case_default_headers + Set default headers + Example: "meta-title", "meta-visualId" view_configuration_type - Pick view type + View type menuItemService.getAvailableViewsAsOptions(true, useCase.processIdentifier) @@ -385,29 +267,97 @@ view_configuration_id <allowedNets> - <allowedNet>tabbed_task_view_configuration</allowedNet> + <allowedNet>task_view_configuration</allowedNet> </allowedNets> </data> <data type="taskRef"> <id>view_configuration_form</id> <title/> </data> + <data type="taskRef"> + <id>view_configuration_all_data_form</id> + <title/> + </data> + <data type="taskRef"> + <id>advanced_content_form</id> + <title/> + <component> + <name>task-list</name> + <property key="headers">meta-caseId,meta-title</property> + </component> + </data> + <data type="number"> + <id>is_tabbed_var_arc</id> + <title>Is tabbed + + + case_empty_content_text + Empty content text + If empty, default text will be used + + + case_empty_content_icon + Empty content icon + If empty, default icon will be used + + 0 + + + icon: f.this, + iconPreview: f.case_empty_content_icon_preview; - + if (icon.value == "") { + change iconPreview value {"""]]>} + return + } + + change iconPreview value { + """]]> + icon.value + """]]> + } + + + + + + case_empty_content_icon_preview + Empty content icon preview + + htmltextarea + + + + case_filter + Filter + Use Elasticsearch string query + * + + case_allow_export Allow export? + + case_allowed_nets + Allowed nets + + + case_all_allowed_nets + All allowed nets? + true + + + case_inherit_allowed_nets + Inherit allowed nets? + true + Názov tlačidla "Nová inštancia" Identifikátor ikony tlačidla "Nová inštancia" Náhľad ikony - Predvolené hlavičky - Napríklad: "meta-title,meta-visualId" - Zvoľte nový filter - Aktualizovať zobrazenie s vybraným filtrom - Typ vyhľadávania prípadov + Predvolené hlavičky + Napríklad: "meta-title", "meta-visualId" + Typ vyhľadávania prípadov Skryté Fulltext Fulltext a rozšírené @@ -415,61 +365,81 @@ Zakázané siete pri vytváraní Uveďte identifikátory procesov oddelené čiarkou. Napríklad: mynet1,mynet2 Zobraziť tlačidlo na vytvorenie prípadu? - Zobrazovať menu pre prípadovú položku? + Zobrazovať menu pre prípadovú položku? Zoraďovanie Vyhľadávanie Upravovanie - Mód hlavičiek - Predvolený mód hlavičiek - Môže byť mód hlavičiek zmenený? - Povoliť tabuľkový mód pre hlavičky? - Použiť vlastné predvolené hlavičky? + Mód hlavičiek + Predvolený mód hlavičiek + Môže byť mód hlavičiek zmenený? + Povoliť tabuľkový mód pre hlavičky? + Použiť vlastné predvolené hlavičky? Nastavenie položky - Filter - Súčasný filter Zobrazenie prípadov Všeobecné - Použiť predvolené hlavičky - Vybrať zobrazenie + Typ zobrazenia Nastavenie - Asociované zobrazenie Povoliť export? + Text prázdneho obsahu + Ak je toto pole prázdne, bude použitý predvolený text + Ikona prázdneho obsahu + Ak je toto pole prázdne, bude použitá predvolená ikona + Náhľad ikony prázdneho obsahu + Filter + Použi Elasticsearch string query + Povolené procesy + Povoliť všetky procesy? + Zdediť povolené procesy? + Filter + Zobrazenie po kliknutí na inštanciu + Tlačidlo vytvorenia inštancie + Hlavičky Schaltflächentitel "Neuer Fall" Ikone ID Ikonevorschau - Anzuzeigende Attributmenge auswählen - Neue Filter auswählen - Beispiel: "meta-title,meta-visualId" + Anzuzeigende Attributmenge auswählen + Beispiel: "meta-title", "meta-visualId" Versteckt Einfacher Suchmodus Sortieren Suchen Bearbeiten - Kopfzeilenmodus - Standardkopfzeilenmodus - Erlaube Änderung des Kopfzeilenmodus? - Erlaube Tabellenmodus? - Eigene Kopfzeilen verwenden? - Filter - Aktueller Filter + Kopfzeilenmodus + Standardkopfzeilenmodus + Erlaube Änderung des Kopfzeilenmodus? + Erlaube Tabellenmodus? + Eigene Kopfzeilen verwenden? Allgemein - Aktualisiere die Ansicht mit dem ausgewählten Filter - Suchmodus im Fallansicht + Suchmodus im Fallansicht Einfacher und erweiterter Suchmodus Erforde den Titel beim erzeugen von Fällen? Ausgeschlossene Prozesse Trenne die Prozessidentifikatoren mit einer Komma. z.B.: netz1,netz2 Schaltfläche „Fall erstellen“ anzeigen? - "Erweiterte Optionen" Taste bei einzelnen Fällen anzeigen + "Erweiterte Optionen" Taste bei einzelnen Fällen anzeigen Menüeintrageinstellungen Fallansicht - Benutzerdefinierte Standardheader verwenden? - Wählen Sie einen Ansichtstyp + Der Ansichtstyp Einstellungen - zugehörige Ansicht Erlaube Export? + Leerer Inhaltstext + Wenn dieses Feld leer ist, wird der Standardtext verwendet + + Leeres Inhaltssymbol + Wenn dieses Feld leer ist, wird das Standardsymbol verwendet + + Vorschau des leeren Inhaltssymbols + Filter + Verwenden Sie Elasticsearch String Query + Erlaubte Prozesse + Alle Prozesse erlauben? + Erlaubte Prozesse erben? + Filter + Ansicht nach dem Klicken auf die Instanz + Schaltfläche zum Erstellen einer Instanz + Kopfzeilen @@ -478,12 +448,32 @@ 208 hourglass_empty + + admin + + true + + + + finish + + + initializeAdvancedForm() + + + data_sync 368 328 + + system + + true + + settings @@ -495,56 +485,54 @@ admin true + + + + default + true - true - true - form_title - 4 + view_dataGroup + 3 grid - view_header + case_view_search_type - visible + editable + required 0 0 1 - 4 + 1 outline - - - filter_update - 4 - grid - Filter - filter_autocomplete_selection + case_show_more_menu editable - + - 0 + 1 0 1 - 3 + 1 outline - update_filter + case_allow_export - visible + editable - 3 + 2 0 1 1 @@ -553,76 +541,69 @@ - selected_filter_preview + case_empty_content_text - visible - + editable + 0 1 1 - 4 + 1 - standard + outline - filter_header + case_empty_content_icon - visible - + editable + - 0 - 2 + 1 + 1 1 - 4 + 1 outline - current_filter_preview + case_empty_content_icon_preview visible - + - 0 - 3 + 2 + 1 1 - 4 + 1 standard - - - view_dataGroup - 4 - grid - view_search_type + case_all_allowed_nets editable - required - + 0 - 0 + 2 1 - 2 + 1 outline - show_create_case_button + case_allowed_nets editable - required - + - 2 - 0 + 1 + 2 1 1 @@ -630,14 +611,13 @@ - show_more_menu + case_inherit_allowed_nets editable - required - + - 3 - 0 + 2 + 2 1 1 @@ -645,122 +625,230 @@ - create_case_button_title + advanced_content_form editable 0 - 1 + 3 1 - 1 - 0 + 3 outline + + + assign_0 + + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + </transition> + <transition> + <id>filter_settings</id> + <x>432</x> + <y>48</y> + <label name="filter_settings">Filter</label> + <icon>filter_alt</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>filter_0</id> + <cols>4</cols> + <layout>grid</layout> <dataRef> - <id>create_case_button_icon</id> + <id>case_filter</id> <logic> <behavior>editable</behavior> </logic> <layout> - <x>1</x> - <y>1</y> + <x>0</x> + <y>0</y> <rows>1</rows> - <cols>1</cols> - <offset>0</offset> + <cols>4</cols> <template>material</template> <appearance>outline</appearance> </layout> </dataRef> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>open_case_settings</id> + <x>336</x> + <y>48</y> + <label name="open_case_settings">Open case view</label> + <icon>queue_play_next</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>associated_view_0</id> + <cols>4</cols> + <layout>grid</layout> <dataRef> - <id>create_case_button_icon_preview</id> + <id>view_configuration_type</id> <logic> <behavior>visible</behavior> </logic> <layout> - <x>2</x> - <y>1</y> + <x>0</x> + <y>0</y> <rows>1</rows> - <cols>1</cols> + <cols>4</cols> <offset>0</offset> <template>material</template> - <appearance>standard</appearance> + <appearance>outline</appearance> </layout> </dataRef> <dataRef> - <id>require_title_in_creation</id> + <id>view_configuration_form</id> <logic> <behavior>editable</behavior> </logic> <layout> - <x>3</x> + <x>0</x> <y>1</y> <rows>1</rows> - <cols>1</cols> + <cols>4</cols> <offset>0</offset> <template>material</template> - <appearance>standard</appearance> + <appearance>outline</appearance> </layout> </dataRef> - <dataRef> - <id>banned_nets_in_creation</id> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>create_case_btn_settings</id> + <x>656</x> + <y>48</y> + <label name="create_case_btn_settings">Create case button</label> + <icon>add_box</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>create_case_btn_0</id> + <cols>3</cols> + <layout>grid</layout> + <dataRef> + <id>show_create_case_button</id> <logic> <behavior>editable</behavior> </logic> <layout> <x>0</x> - <y>2</y> + <y>0</y> <rows>1</rows> - <cols>4</cols> - <offset>0</offset> + <cols>1</cols> <template>material</template> <appearance>outline</appearance> </layout> </dataRef> - </dataGroup> - <dataGroup> - <id>view_headers</id> - <cols>5</cols> - <layout>grid</layout> <dataRef> - <id>is_header_mode_changeable</id> + <id>require_title_in_creation</id> <logic> <behavior>editable</behavior> - <behavior>required</behavior> - <action trigger="set"> - trans: t.this, - isChangeable: f.is_header_mode_changeable, - mode: f.headers_mode, - defaultMode: f.headers_default_mode; - - make [mode, defaultMode], editable on trans when { isChangeable.value } - make [mode, defaultMode], required on trans when { isChangeable.value } - - make [mode, defaultMode], hidden on trans when { !isChangeable.value } - make [mode, defaultMode], optional on trans when { !isChangeable.value } - </action> </logic> <layout> - <x>0</x> + <x>1</x> <y>0</y> <rows>1</rows> <cols>1</cols> <offset>0</offset> <template>material</template> + <appearance>standard</appearance> + </layout> + </dataRef> + <dataRef> + <id>create_case_button_title</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> <appearance>outline</appearance> </layout> </dataRef> <dataRef> - <id>allow_header_table_mode</id> + <id>create_case_button_icon</id> <logic> <behavior>editable</behavior> - <behavior>required</behavior> </logic> <layout> <x>1</x> - <y>0</y> + <y>1</y> <rows>1</rows> <cols>1</cols> <offset>0</offset> @@ -769,29 +857,96 @@ </layout> </dataRef> <dataRef> - <id>headers_mode</id> + <id>create_case_button_icon_preview</id> <logic> - <behavior>editable</behavior> - <behavior>required</behavior> + <behavior>visible</behavior> </logic> <layout> <x>2</x> - <y>0</y> + <y>1</y> <rows>1</rows> - <cols>2</cols> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + <appearance>standard</appearance> + </layout> + </dataRef> + <dataRef> + <id>banned_nets_in_creation</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>2</y> + <rows>1</rows> + <cols>3</cols> <offset>0</offset> <template>material</template> <appearance>outline</appearance> </layout> </dataRef> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>header_settings</id> + <x>560</x> + <y>48</y> + <label name="header_settings">Header</label> + <icon>view_column</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>header_0</id> + <cols>3</cols> + <layout>grid</layout> <dataRef> - <id>headers_default_mode</id> + <id>case_is_header_mode_changeable</id> <logic> <behavior>editable</behavior> <behavior>required</behavior> + <action trigger="set"> + trans: t.this, + isChangeable: f.case_is_header_mode_changeable, + mode: f.case_headers_mode, + defaultMode: f.case_headers_default_mode; + + make [mode, defaultMode], editable on trans when { isChangeable.value } + make [mode, defaultMode], required on trans when { isChangeable.value } + + make [mode, defaultMode], hidden on trans when { !isChangeable.value } + make [mode, defaultMode], optional on trans when { !isChangeable.value } + </action> </logic> <layout> - <x>4</x> + <x>0</x> <y>0</y> <rows>1</rows> <cols>1</cols> @@ -807,15 +962,15 @@ <action trigger="set"> trans: t.this, use: f.use_case_default_headers, - headers: f.default_headers; + headers: f.case_default_headers; make headers,editable on trans when { use.value } make headers,visible on trans when { !use.value } </action> </logic> <layout> - <x>0</x> - <y>1</y> + <x>1</x> + <y>0</y> <rows>1</rows> <cols>1</cols> <offset>0</offset> @@ -824,96 +979,247 @@ </layout> </dataRef> <dataRef> - <id>default_headers</id> + <id>case_default_headers</id> <logic> <behavior>editable</behavior> </logic> <layout> - <x>1</x> - <y>1</y> + <x>2</x> + <y>0</y> <rows>1</rows> - <cols>4</cols> + <cols>1</cols> <offset>0</offset> <template>material</template> <appearance>outline</appearance> </layout> </dataRef> - </dataGroup> - <dataGroup> - <id>associated_view</id> - <cols>4</cols> - <layout>grid</layout> - <title name="associated_view">Associated view - view_configuration_type + case_allow_header_table_mode editable + required 0 - 0 + 1 1 - 4 + 1 0 outline - - 0 - - - view_configuration_type: f.view_configuration_type, - view_configuration_form: f.view_configuration_form, - view_configuration_id: f.view_configuration_id; - - if (view_configuration_id.value != null && !view_configuration_id.value.isEmpty()) { - workflowService.deleteCase(view_configuration_id.value[0]) - } - - if (view_configuration_type.value == null || view_configuration_type.value == "") { - change view_configuration_id value { [] } - change view_configuration_form value { [] } - return - } - - def configurationCase = createCase(view_configuration_type.value + "_configuration") - def initTask = assignTask("initialize", configurationCase) - finishTask(initTask) - configurationCase = workflowService.findOne(configurationCase.stringId) - change view_configuration_id value { [configurationCase.stringId] } - change view_configuration_form value { [configurationCase.tasks.find { it.transition == "settings" }.task] } - - - - view_configuration_form + case_headers_mode editable + required - 0 + 1 1 1 - 4 + 1 0 outline - case_allow_export + case_headers_default_mode - hidden + editable + required - 0 - 999 + 2 + 1 1 1 + 0 + + outline
    + + assign + + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>all_menu_data</id> + <x>10</x> + <y>10</y> + <label>All menu data</label> + <roleRef> + <id>system</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>all_menu_data_0</id> + <layout>flow</layout> + <alignment>start</alignment> + <stretch>true</stretch> + <dataRef> + <id>case_filter</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_view_search_type</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>show_create_case_button</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_show_more_menu</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_empty_content_text</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_empty_content_icon</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_empty_content_icon_preview</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_all_allowed_nets</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_allowed_nets</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_inherit_allowed_nets</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>create_case_button_title</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>create_case_button_icon</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>create_case_button_icon_preview</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>require_title_in_creation</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>banned_nets_in_creation</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_is_header_mode_changeable</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_allow_header_table_mode</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_headers_mode</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_headers_default_mode</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>use_case_default_headers</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_default_headers</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>view_configuration_type</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>view_configuration_all_data_form</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_allow_export</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + </dataGroup> </transition> <place> <id>initialized</id> @@ -931,6 +1237,22 @@ <tokens>1</tokens> <static>false</static> </place> + <place> + <id>is_tabbed</id> + <x>240</x> + <y>48</y> + <label>is_tabbed</label> + <tokens>0</tokens> + <static>false</static> + </place> + <place> + <id>is_untabbed</id> + <x>112</x> + <y>144</y> + <label>is_untabbed</label> + <tokens>0</tokens> + <static>false</static> + </place> <arc> <id>a1</id> <type>read</type> @@ -952,4 +1274,47 @@ <destinationId>initialized</destinationId> <multiplicity>1</multiplicity> </arc> + <arc> + <id>a4</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>filter_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a5</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>open_case_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a6</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>header_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a7</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>create_case_btn_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a8</id> + <type>regular</type> + <sourceId>initialize</sourceId> + <destinationId>is_tabbed</destinationId> + <multiplicity>1</multiplicity> + <reference>is_tabbed_var_arc</reference> + </arc> + <arc> + <id>a9</id> + <type>read</type> + <sourceId>is_tabbed</sourceId> + <destinationId>open_case_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> </document> \ No newline at end of file diff --git a/src/main/resources/petriNets/engine-processes/menu/menu_item.xml b/src/main/resources/petriNets/engine-processes/menu/menu_item.xml index 8fe4ae4c9f7..c12ae83df96 100644 --- a/src/main/resources/petriNets/engine-processes/menu/menu_item.xml +++ b/src/main/resources/petriNets/engine-processes/menu/menu_item.xml @@ -25,8 +25,6 @@ <roleRef> <id>default</id> <caseLogic> - <create>false</create> - <delete>false</delete> <view>true</view> </caseLogic> </roleRef> @@ -50,6 +48,25 @@ <id>admin</id> <title>Admin + + { -> + def advancedContentFormField = useCase.getField("advanced_content_form") + def taskIds = [useCase.tasks.find { taskPair -> taskPair.transition == "role_settings"}.task, + useCase.tasks.find { taskPair -> taskPair.transition == "view_settings"}.task] + + def viewConfigurationIdDataField = useCase.getDataField("view_configuration_id") + if (viewConfigurationIdDataField.value != null && !viewConfigurationIdDataField.value.isEmpty()) { + def viewCase = workflowService.findOne(viewConfigurationIdDataField.value[0]) + def taskIdsFromView = viewCase.getFieldValue("advanced_content_form") + if (taskIdsFromView != null) { + taskIds.addAll(taskIdsFromView) + make ["advanced_content_form"], hidden on (viewCase.tasks.findAll { it.transition == "settings" }?.task as List) when { true } + } + } + + change advancedContentFormField value { taskIds } + } + { -> @@ -95,7 +112,7 @@ } - { boolean useTabIcon, boolean useTabbedView, String transId = "item_settings" -> + { boolean useTabIcon, boolean useTabbedView, String transId = "view_settings" -> def settingsTrans = useCase.petriNet.transitions[transId] make [useCase.getField("use_tab_icon"), useCase.getField("tab_icon"), useCase.getField("tab_name")], @@ -195,6 +212,7 @@ prefixUri = prefixUri.replace("//","/") String newUri = prefixUri + uriService.getUriSeparator() + newNodeName.value + newUri = newUri.replace("//","/") def newNode = uriService.getOrCreate(newUri, com.netgrif.application.engine.petrinet.domain.UriContentType.CASE) change selectedUri value { splitUriPath(newNode.uriPath) } @@ -241,6 +259,10 @@ menu_item_identifier Menu item identifier + + menu_item_identifier_on_create + Menu item identifier + nodePath Item URI @@ -291,7 +313,7 @@ menu_name_as_visible Name of the item - Is shown in the menu + Will be shown in the menu autocomplete @@ -382,7 +404,11 @@ processes: f.this; - change processes options { return configurableMenuService.getNetsByAuthorAsMapOptions(loggedUser(), org.springframework.context.i18n.LocaleContextHolder.locale) } + try { + change processes options { return configurableMenuService.getNetsByAuthorAsMapOptions(loggedUser(), org.springframework.context.i18n.LocaleContextHolder.locale) } + } catch (Exception e) { + log.error("Cannot resolve processes: ", e) + } processes: f.this, @@ -445,6 +471,18 @@ use_tabbed_view Do you want to use view with tabs? + true + + 0 + + + use_tabbed_view: f.use_tabbed_view, + use_tab_icon: f.use_tab_icon; + + manageBehaviorOfTabFields(use_tab_icon.value, use_tabbed_view.value) + + + @@ -468,7 +506,7 @@ tab_icon_preview - Tab icon preview + Tab icon preview htmltextarea @@ -482,12 +520,15 @@ tab_name Name of the item Will be shown in tab + + new com.netgrif.application.engine.petrinet.domain.I18nString("View", [sk: "Zobrazenie", de: "Die Ansicht"]) + view_configuration_type - Pick view type + View type - menuItemService.getAvailableViewsAsOptions(false, true) + menuItemService.getAvailableViewsAsOptions(true, true) use_tabbed_view: f.use_tabbed_view, @@ -502,15 +543,20 @@ view_configuration_id <allowedNets> - <allowedNet>tabbed_case_view_configuration</allowedNet> - <allowedNet>tabbed_task_view_configuration</allowedNet> + <allowedNet>case_view_configuration</allowedNet> + <allowedNet>task_view_configuration</allowedNet> <allowedNet>tabbed_ticket_view_configuration</allowedNet> + <allowedNet>single_task_view_configuration</allowedNet> </allowedNets> </data> <data type="taskRef"> <id>view_configuration_form</id> <title/> </data> + <data type="taskRef"> + <id>view_configuration_all_data_form</id> + <title/> + </data> <data type="button"> <id>order_down</id> <title/> @@ -593,6 +639,28 @@ ]) </action> </data> + <data type="i18n"> + <id>role_divider</id> + <title/> + <component> + <name>divider</name> + </component> + </data> + <data type="taskRef"> + <id>advanced_content_form</id> + <title/> + <component> + <name>task-list</name> + <property key="headers">meta-title</property> + </component> + </data> + <data type="enumeration_map"> + <id>configuration_templates</id> + <title name="configuration_templates">Configuration template + + com.netgrif.application.engine.menu.service.MenuItemTemplateHolder.transformToOptions() + + @@ -614,6 +682,7 @@ Bude zobrazený v menu Identifikátor ikony v karte Identifikátor Material ikony. Zoznam ikon s identifikátormi je dostupný online. + Náhľad ikony v karte Zobraziť ikonu v karte? Názov položky Bude zobrazený v karte @@ -630,7 +699,6 @@ Zoznam povolených rolí, ktoré môžu zobraziť túto položku Zakázané roly Zoznam zakázaných rolí, ktoré nemôžu zobraziť túto položku - Všeobecné Identifikátor položky URI položky Nový uzol @@ -640,8 +708,14 @@ Automatické zvolenie zobrazenia Po automatickom zvolení sa dané zobrazenie používateľovi otvorí Použiť zobrazenie v taboch? - Vybrať zobrazenie + Typ zobrazenia Nastavenie zobrazenia + Vytvoriť menu položku + Zoradiť pod-položky + Vytvoriť menu položku + Konfiguračná šablóna + Rola + Zobrazenie Ikonevorschau @@ -658,7 +732,6 @@ Beispiel: "demo-tabbed-views" Rollen Zulässige Rollen - Allgemein Identifikationsnummer des Menüeintrages Menüeintrag-URI Neuer Knoten @@ -670,6 +743,7 @@ Titel des Eintrages Wird im Menü angezeigt Ikonen Identifikator der Registerkarte + Vorschau der Registerkarte Ikone Zeige die Registerkarte Ikone an? Titel der Registerkarte Wird in der Registerkarte angezeigt @@ -688,8 +762,14 @@ Automatische Anzeigeauswahl Wenn ausgewählt, wird die Ansicht automatisch geöffnet Möchten Sie die Ansicht mit Registerkarten verwenden? - Wählen Sie einen Ansichtstyp + Der Ansichtstyp Die Ansichtskonfiguration + Menüeintrag erstellen + Untereintrage sortieren + Erstellen + Konfigurationsvorlage + Rolle + Ansicht @@ -697,56 +777,27 @@ initialize 340 220 - + + + true + hourglass_empty - - admin - - true - true - true - true - - - - - data_sync - 340 - 340 - - - system - - true - - - - - - item_settings - 460 - 100 - - settings auto admin true - true - true - true - general_0 + initialize_0 4 grid - General - menu_item_identifier + menu_name - visible + editable + required 0 @@ -756,11 +807,34 @@ outline + + 0 + + + menu_item_identifier: f.menu_item_identifier_on_create, + menu_name: f.menu_name; + + if (menu_item_identifier.value != null && !menu_item_identifier.value.isEmpty() + || menu_name.value == null) { + return + } + + String defaultName = menu_name.value.defaultValue + if (defaultName == null || defaultName.isEmpty()) { + defaultName = menu_name.value.translations?.values()?.find() + } + + String identifier = com.netgrif.application.engine.menu.utils.MenuItemUtils.sanitize(defaultName) + change menu_item_identifier value { identifier } + + + - nodePath + menu_item_identifier_on_create - visible + editable + required 2 @@ -770,11 +844,33 @@ outline + + 0 + + + menu_item_identifier: f.menu_item_identifier_on_create; + + if (menuItemService.existsMenuItem(menu_item_identifier.value)) { + change menu_item_identifier validations { validation('''regex $.^''', + new com.netgrif.application.engine.petrinet.domain.I18nString("Such menu item already exists", + [sk: "Taká položka menu už existuje", de: "Ein solcher Menüeintrag existiert bereits"])) + } + } else { + change menu_item_identifier validations { null } + String sanitizedIdentifier = com.netgrif.application.engine.menu.utils.MenuItemUtils.sanitize(menu_item_identifier.value) + if (menu_item_identifier.value != sanitizedIdentifier) { + change menu_item_identifier value { sanitizedIdentifier } + } + } + + + - menu_name + move_dest_uri editable + required 0 @@ -786,7 +882,7 @@ - menu_icon + move_dest_uri_new_node editable @@ -800,9 +896,9 @@ - menu_icon_preview + move_add_node - visible + editable 3 @@ -810,359 +906,233 @@ 1 1 - standard + outline - is_auto_select + configuration_templates editable + required - 1 + 0 2 1 - 1 + 4 - standard + outline + + finish + + + def outcome = menuItemService.handleConfigurationTemplate(useCase) + outcome.getMapping().each { fieldId, value -> + change useCase.getField(fieldId) value { value } + } + + + trans: t.view_settings, + useTabIcon: f.use_tab_icon, + view_configuration_form: f.view_configuration_form, + view_configuration_type: f.view_configuration_type, + tabIconPreview: f.tab_icon_preview, + tabName: f.tab_name, + tabIcon: f.tab_icon, + use_custom_view: f.use_custom_view, + selector: f.custom_view_selector; + + if (use_custom_view.value) { + make selector, editable on trans when { true } + make [useTabIcon, tabIconPreview, tabName, tabIcon, view_configuration_form, + view_configuration_type], hidden on trans when { true } + } + + + + + initializeAdvancedForm() + + + name: f.menu_name, + menu_item_identifier: f.menu_item_identifier, + menu_item_identifier_on_create: f.menu_item_identifier_on_create, + dest: f.move_dest_uri; + + change menu_item_identifier value { menu_item_identifier_on_create.value } + + String newUri = dest.value.join("/") + newUri = newUri.replace("//","/") + + changeMenuItem useCase uri { newUri } + + + Create + + + + data_sync + 340 + 112 + + + system + + true + + + + + + item_settings + 460 + 100 + + + true + + settings + auto + + admin + + true + + + + default + + true + + - roles_management - 5 + general_0 + 4 grid - Roles - processes_available + menu_item_identifier - editable + visible 0 0 - 2 - 1 - 0 + 1 + 2 outline - roles_available + nodePath - editable + visible - 1 + 2 0 - 2 - 1 - 0 + 1 + 2 outline - add_allowed_roles + configuration_templates - editable + visible - 2 - 0 + 0 + 1 1 - 1 - 0 + 2 + outline - allowed_roles + menu_name editable - 3 - 0 + 2 + 1 1 - 1 - 0 + 2 outline - remove_allowed_roles + menu_icon editable - 4 - 0 + 0 + 2 1 - 1 - 0 + 2 + outline - add_banned_roles + menu_icon_preview - editable + visible 2 - 1 + 2 1 - 1 - 0 + 2 + standard - banned_roles + is_auto_select editable - 3 - 1 + 0 + 3 1 - 1 - 0 + 2 - outline + standard - remove_banned_roles + advanced_content_form editable - 4 - 1 + 0 + 4 1 - 1 - 0 + 4 + outline - - configuration_view - 4 - grid - View configuration - - use_custom_view - - editable - - - 0 - 0 - 1 - 1 - - outline - - - 0 - - - trans: t.this, - useTabIcon: f.use_tab_icon, - use_tabbed_view: f.use_tabbed_view, - view_configuration_form: f.view_configuration_form, - view_configuration_type: f.view_configuration_type, - tabIconPreview: f.tab_icon_preview, - tabName: f.tab_name, - tabIcon: f.tab_icon, - use: f.use_custom_view, - selector: f.custom_view_selector; - - if (use.value) { - make selector, editable on trans when { true } - make [useTabIcon, tabIconPreview, tabName, tabIcon, use_tabbed_view, view_configuration_form, - view_configuration_type], hidden on trans when { true } - // todo remove configuration or keep it? - } else { - manageBehaviorOfTabFields(useTabIcon.value, use_tabbed_view.value) - make [use_tabbed_view, view_configuration_form, view_configuration_type], editable on trans when { true } - make selector, hidden on trans when { true } - } - - - - - - custom_view_selector - - hidden - - - 1 - 0 - 1 - 3 - - outline - - - - use_tabbed_view - - editable - - - 1 - 0 - 1 - 1 - - standard - - - 0 - - - use_tabbed_view: f.use_tabbed_view, - use_tab_icon: f.use_tab_icon, - view_configuration_type: f.view_configuration_type; - - manageBehaviorOfTabFields(use_tab_icon.value, use_tabbed_view.value) - - change view_configuration_type value { null } - change view_configuration_type options { menuItemService.getAvailableViewsAsOptions(use_tabbed_view.value, true) } - - - - - - tab_name - - hidden - - - 2 - 0 - 1 - 1 - - outline - - - - use_tab_icon - - hidden - - - 3 - 0 - 1 - 1 - 0 - - - - 0 - - - use_tabbed_view: f.use_tabbed_view, - useIcon: f.use_tab_icon; - - manageBehaviorOfTabFields(useIcon.value, use_tabbed_view.value) - - - - - - tab_icon - - hidden - - - 0 - 1 - 1 - 1 - - outline - - - - tab_icon_preview - - hidden - - - 1 - 1 - 1 - 2 - - standard - - - - view_configuration_type - - editable - - - 0 - 2 - 1 - 4 - - outline - - - 0 - - - view_configuration_type: f.view_configuration_type, - view_configuration_form: f.view_configuration_form, - view_configuration_id: f.view_configuration_id; - - if (view_configuration_id.value != null && !view_configuration_id.value.isEmpty()) { - workflowService.deleteCase(view_configuration_id.value[0]) - } - - if (view_configuration_type.value == null || view_configuration_type.value == "") { - change view_configuration_id value { [] } - change view_configuration_form value { [] } - return - } - - def configurationCase = createCase(view_configuration_type.value + "_configuration") - def initTask = assignTask("initialize", configurationCase) - finishTask(initTask) - configurationCase = workflowService.findOne(configurationCase.stringId) - change view_configuration_id value { [configurationCase.stringId] } - change view_configuration_form value { [configurationCase.tasks.find { it.transition == "settings" }.task] } - - - - - - view_configuration_form - - editable - - - 0 - 3 - 1 - 4 - - outline - - - + + assign_0 + + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> </transition> <transition> @@ -1170,15 +1140,15 @@ <x>580</x> <y>100</y> <label name="move_item">Move item</label> + <tags> + <tag key="visible">true</tag> + </tags> <icon>move_down</icon> <assignPolicy>auto</assignPolicy> <roleRef> <id>admin</id> <logic> <perform>true</perform> - <view>true</view> - <cancel>true</cancel> - <assign>true</assign> </logic> </roleRef> <dataGroup> @@ -1254,15 +1224,15 @@ <x>580</x> <y>340</y> <label name="duplicate_item">Duplicate item</label> + <tags> + <tag key="visible">true</tag> + </tags> <icon>content_copy</icon> <assignPolicy>auto</assignPolicy> <roleRef> <id>admin</id> <logic> <perform>true</perform> - <view>true</view> - <cancel>true</cancel> - <assign>true</assign> </logic> </roleRef> <dataGroup> @@ -1318,16 +1288,16 @@ <id>children_order</id> <x>580</x> <y>220</y> - <label>Manage item order</label> + <label name="children_order">Manage item order</label> + <tags> + <tag key="visible">true</tag> + </tags> <icon>low_priority</icon> <assignPolicy>auto</assignPolicy> <roleRef> <id>admin</id> <logic> <perform>true</perform> - <view>true</view> - <cancel>true</cancel> - <assign>true</assign> </logic> </roleRef> <dataGroup> @@ -1366,9 +1336,6 @@ <id>system</id> <logic> <perform>true</perform> - <view>true</view> - <cancel>true</cancel> - <assign>true</assign> </logic> </roleRef> <dataGroup> @@ -1436,73 +1403,624 @@ </dataGroup> <event type="finish"> <id>finish</id> - <title> + </event> <event type="delegate"> <id>delegate</id> - <title> + </event> </transition> - - <!-- PLACES--> - <place> - <id>uninitialized</id> - <x>220</x> - <y>220</y> - <label>uninitialized</label> - <tokens>1</tokens> - <static>false</static> - </place> - <place> - <id>initialized</id> - <x>460</x> - <y>220</y> - <label>initialized</label> - <tokens>0</tokens> - <static>false</static> - </place> - - <!-- ARCS--> - <arc> - <id>a1</id> - <type>regular</type> - <sourceId>uninitialized</sourceId> - <destinationId>initialize</destinationId> - <multiplicity>1</multiplicity> - </arc> - <arc> - <id>a7</id> - <type>read</type> - <sourceId>initialized</sourceId> - <destinationId>item_settings</destinationId> - <multiplicity>1</multiplicity> - </arc> - <arc> - <id>a8</id> - <type>regular</type> - <sourceId>initialize</sourceId> - <destinationId>initialized</destinationId> - <multiplicity>1</multiplicity> - </arc> - <arc> - <id>a9</id> - <type>read</type> - <sourceId>initialized</sourceId> - <destinationId>move_item</destinationId> - <multiplicity>1</multiplicity> - </arc> - <arc> - <id>a10</id> - <type>read</type> - <sourceId>initialized</sourceId> - <destinationId>duplicate_item</destinationId> - <multiplicity>1</multiplicity> - </arc> - <arc> - <id>a13</id> - <type>read</type> - <sourceId>initialized</sourceId> - <destinationId>children_order</destinationId> + <transition> + <id>system_initialize</id> + <x>336</x> + <y>304</y> + <label>System create</label> + <icon>computer</icon> + <roleRef> + <id>system</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <event type="finish"> + <id>finish</id> + <actions phase="pre"> + <action> + trans: t.view_settings, + useTabIcon: f.use_tab_icon, + view_configuration_form: f.view_configuration_form, + view_configuration_type: f.view_configuration_type, + tabIconPreview: f.tab_icon_preview, + tabName: f.tab_name, + tabIcon: f.tab_icon, + use_custom_view: f.use_custom_view, + selector: f.custom_view_selector; + + if (use_custom_view.value) { + make selector, editable on trans when { true } + make [useTabIcon, tabIconPreview, tabName, tabIcon, view_configuration_form, + view_configuration_type], hidden on trans when { true } + } + </action> + </actions> + <actions phase="post"> + <action> + initializeAdvancedForm() + </action> + </actions> + </event> + </transition> + <transition> + <id>role_settings</id> + <x>400</x> + <y>48</y> + <label name="role_settings">Role</label> + <icon>person</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>roles_management</id> + <cols>3</cols> + <layout>grid</layout> + <dataRef> + <id>processes_available</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>0</y> + <rows>2</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>roles_available</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>1</x> + <y>0</y> + <rows>2</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>add_allowed_roles</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>2</x> + <y>0</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + </layout> + </dataRef> + <dataRef> + <id>add_banned_roles</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>2</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + </layout> + </dataRef> + <dataRef> + <id>role_divider</id> + <logic> + <behavior>visible</behavior> + </logic> + <layout> + <x>0</x> + <y>2</y> + <rows>1</rows> + <cols>3</cols> + <offset>0</offset> + <template>material</template> + </layout> + </dataRef> + <dataRef> + <id>allowed_roles</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>3</y> + <rows>1</rows> + <cols>2</cols> + <offset>0</offset> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>remove_allowed_roles</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>2</x> + <y>3</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + </layout> + </dataRef> + <dataRef> + <id>banned_roles</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>4</y> + <rows>1</rows> + <cols>2</cols> + <offset>0</offset> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>remove_banned_roles</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>2</x> + <y>4</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + </layout> + </dataRef> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>view_settings</id> + <x>528</x> + <y>48</y> + <label name="view_settings">View</label> + <icon>image</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>configuration_view</id> + <cols>3</cols> + <layout>grid</layout> + <dataRef> + <id>view_configuration_type</id> + <logic> + <behavior>visible</behavior> + </logic> + <layout> + <x>0</x> + <y>0</y> + <rows>1</rows> + <cols>1</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>tab_name</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>1</x> + <y>0</y> + <rows>1</rows> + <cols>2</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>custom_view_selector</id> + <logic> + <behavior>hidden</behavior> + </logic> + <layout> + <x>0</x> + <y>0</y> + <rows>1</rows> + <cols>3</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>use_tab_icon</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + </layout> + <event type="set"> + <id>0</id> + <actions phase="post"> + <action> + use_tabbed_view: f.use_tabbed_view, + useIcon: f.use_tab_icon; + + manageBehaviorOfTabFields(useIcon.value, use_tabbed_view.value) + </action> + </actions> + </event> + </dataRef> + <dataRef> + <id>tab_icon</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>1</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>tab_icon_preview</id> + <logic> + <behavior>visible</behavior> + </logic> + <layout> + <x>2</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <template>material</template> + <appearance>standard</appearance> + </layout> + </dataRef> + <dataRef> + <id>view_configuration_form</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>3</y> + <rows>1</rows> + <cols>2</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>all_menu_data</id> + <x>10</x> + <y>10</y> + <label>All menu data</label> + <roleRef> + <id>system</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>all_menu_data_0</id> + <layout>flow</layout> + <alignment>start</alignment> + <stretch>true</stretch> + <dataRef> + <id>menu_item_identifier</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>nodePath</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>menu_name</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>menu_icon</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>menu_icon_preview</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>hasChildren</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>is_auto_select</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>processes_available</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>roles_available</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>add_allowed_roles</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>allowed_roles</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>remove_allowed_roles</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>add_banned_roles</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>banned_roles</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>remove_banned_roles</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>use_custom_view</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>custom_view_selector</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>use_tabbed_view</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>tab_name</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>use_tab_icon</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>tab_icon</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>tab_icon_preview</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>view_configuration_type</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>view_configuration_all_data_form</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + </dataGroup> + </transition> + + <!-- PLACES--> + <place> + <id>uninitialized</id> + <x>220</x> + <y>220</y> + <label>uninitialized</label> + <tokens>1</tokens> + <static>false</static> + </place> + <place> + <id>initialized</id> + <x>460</x> + <y>220</y> + <label>initialized</label> + <tokens>0</tokens> + <static>false</static> + </place> + + <!-- ARCS--> + <arc> + <id>a1</id> + <type>regular</type> + <sourceId>uninitialized</sourceId> + <destinationId>initialize</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a7</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>item_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a8</id> + <type>regular</type> + <sourceId>initialize</sourceId> + <destinationId>initialized</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a9</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>move_item</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a10</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>duplicate_item</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a13</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>children_order</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a14</id> + <type>regular</type> + <sourceId>uninitialized</sourceId> + <destinationId>system_initialize</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a15</id> + <type>regular</type> + <sourceId>system_initialize</sourceId> + <destinationId>initialized</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a16</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>view_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a17</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>role_settings</destinationId> <multiplicity>1</multiplicity> </arc> </document> \ No newline at end of file diff --git a/src/main/resources/petriNets/engine-processes/menu/single_task_view_configuration.xml b/src/main/resources/petriNets/engine-processes/menu/single_task_view_configuration.xml new file mode 100644 index 00000000000..2929462fd3a --- /dev/null +++ b/src/main/resources/petriNets/engine-processes/menu/single_task_view_configuration.xml @@ -0,0 +1,334 @@ +<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://petriflow.com/petriflow.schema.xsd"> + <id>single_task_view_configuration</id> + <initials>TST</initials> + <title>Single task view configuration + check_box_outline_blank + true + false + false + + system + + true + true + true + + + + admin + + true + true + true + + + + default + + true + + + + system + System + + + admin + Admin + + + + { -> + def advancedContentFormField = useCase.getField("advanced_content_form") + change advancedContentFormField value { [useCase.tasks.find { taskPair -> taskPair.transition == "filter_settings"}.task] } + } + + + + advanced_content_form + + <component> + <name>task-list</name> + <property key="headers">meta-title</property> + </component> + </data> + <data type="boolean"> + <id>show_page_header</id> + <title name="show_page_header">Show page header + true + + + show_page_footer + Show page footer + false + + + task_filter + Filter + Use Elasticsearch string query + * + + + + + Vybrať zobrazenie + Nastavenie + Zobraziť hlavičku stránky + Zobraziť pätu stránky + Filter + Použi Elasticsearch string query + Filter + + + Wählen Sie einen Ansichtstyp + Einstellungen + Seitenkopf anzeigen + Seitenfuß anzeigen + Filter + Elasticsearch-String-Abfrage verwenden + Filter + + + + initialize + 368 + 208 + + hourglass_empty + + admin + + true + + + + finish + + + initializeAdvancedForm() + + + + + + data_sync + 368 + 328 + + + system + + true + + + + + settings + 496 + 112 + + settings + + admin + + true + + + + default + + true + + + + view_dataGroup + 4 + grid + + show_page_header + + editable + + + 0 + 0 + 1 + 2 + + outline + + + + show_page_footer + + editable + + + 2 + 0 + 1 + 2 + + outline + + + + advanced_content_form + + editable + + + 0 + 1 + 1 + 4 + + outline + + + + + assign_0 + + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + </transition> + <transition> + <id>filter_settings</id> + <x>432</x> + <y>48</y> + <label name="filter_settings">Filter</label> + <icon>filter_alt</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>filter_0</id> + <cols>4</cols> + <layout>grid</layout> + <dataRef> + <id>task_filter</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>0</y> + <rows>1</rows> + <cols>4</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>all_menu_data</id> + <x>10</x> + <y>10</y> + <label>All menu data</label> + <roleRef> + <id>system</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>all_menu_data_0</id> + <layout>flow</layout> + <alignment>start</alignment> + <stretch>true</stretch> + <dataRef> + <id>show_page_header</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>show_page_footer</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_filter</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + </dataGroup> + </transition> + <place> + <id>initialized</id> + <x>496</x> + <y>208</y> + <label>initialized</label> + <tokens>0</tokens> + <static>false</static> + </place> + <place> + <id>uninitialized</id> + <x>240</x> + <y>208</y> + <label>uninitialized</label> + <tokens>1</tokens> + <static>false</static> + </place> + <arc> + <id>a1</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a2</id> + <type>regular</type> + <sourceId>uninitialized</sourceId> + <destinationId>initialize</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a3</id> + <type>regular</type> + <sourceId>initialize</sourceId> + <destinationId>initialized</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a4</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>filter_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> +</document> \ No newline at end of file diff --git a/src/main/resources/petriNets/engine-processes/menu/tabbed_single_task_view_configuration.xml b/src/main/resources/petriNets/engine-processes/menu/tabbed_single_task_view_configuration.xml deleted file mode 100644 index 10c34b150e8..00000000000 --- a/src/main/resources/petriNets/engine-processes/menu/tabbed_single_task_view_configuration.xml +++ /dev/null @@ -1,316 +0,0 @@ -<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://petriflow.com/petriflow.schema.xsd"> - <id>tabbed_single_task_view_configuration</id> - <initials>TST</initials> - <title>Tabbed single task view configuration - check_box_outline_blank - true - false - false - - system - - true - true - true - - - - admin - - true - true - true - - - - default - - false - false - true - - - - system - System - - - admin - Admin - - - - { - com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField filterAutocomplete, - com.netgrif.application.engine.petrinet.domain.dataset.TaskField previewTaskRef, - com.netgrif.application.engine.petrinet.domain.dataset.CaseField selectedFilterRef, - com.netgrif.application.engine.petrinet.domain.dataset.ButtonField updateBtn, - com.netgrif.application.engine.petrinet.domain.Transition trans - -> - if (filterAutocomplete.getOptions().containsKey(filterAutocomplete.value)) { - change previewTaskRef value { - return [findTask({it.caseId.eq(filterAutocomplete.value).and(it.transitionId.eq("view_filter"))}).stringId] - } - make updateBtn,editable on trans when { true } - } else { - change filterAutocomplete options { - def findAllPredicate = { filterCase -> !selectedFilterRef.value.contains(filterCase.stringId) - && filterCase.dataSet["filter_type"].value == "Case" } - return findFilters(filterAutocomplete.value != null ? filterAutocomplete.value : "") - .findAll(findAllPredicate) - .collectEntries({filterCase -> [filterCase.stringId, filterCase.title]}) - } - change previewTaskRef value { [] } - make updateBtn,visible on trans when { true } - } - } - - - - - selected_filter_preview - - </data> - <data type="taskRef"> - <id>current_filter_preview</id> - <title/> - </data> - <data type="i18n"> - <id>filter_header</id> - <title/> - <init name="filter_header">Current filter</init> - <component> - <name>divider</name> - </component> - </data> - <data type="text"> - <id>new_filter_id</id> - <title/> - </data> - <data type="boolean" immediate="true"> - <id>contains_filter</id> - <title/> - <init>false</init> - </data> - <data type="enumeration_map"> - <id>filter_autocomplete_selection</id> - <title name="filter_autocomplete_selection">Select new filter - - autocomplete_dynamic - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - - update_filter - - <placeholder name="update_filter">Update view with selected filter</placeholder> - <component> - <name>raised</name> - </component> - <action trigger="set"> - trans: t.settings, - update_filter: f.update_filter, - contains_filter: f.contains_filter, - filter_case: f.filter_case, - filterAutocomplete: f.filter_autocomplete_selection; - - boolean containsFilter = filterAutocomplete.value != null && filterAutocomplete.value != "" - if (containsFilter) { - def filterCase = findCase({it._id.eq(filterAutocomplete.value)}) - if (filterCase.dataSet["filter_type"].value != "Task") { - throw new IllegalArgumentException("Filter is of wrong type. Only filter of Task type allowed.") - } - } - - change contains_filter value { containsFilter } - change filter_case value { [filterAutocomplete.value] } - change filterAutocomplete value { "" } - make update_filter,visible on trans when { true } - </action> - </data> - <data type="caseRef"> - <id>filter_case</id> - <title/> - <action trigger="set"> - filterTaskRef: f.current_filter_preview, - contains_filter: f.contains_filter, - filterCaseRef: f.filter_case; - - if (filterCaseRef.value == null || filterCaseRef.value == []) { - change filterTaskRef value { [] } - change contains_filter value { false } - return - } - - def filterCase = findCase({it._id.eq(filterCaseRef.value[0])}) - change filterTaskRef value { - return [findTask({it.caseId.eq(filterCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId] - } - change contains_filter value { true } - </action> - <allowedNets> - <allowedNet>filter</allowedNet> - </allowedNets> - </data> - - <!-- VIEW CONFIGURATION DATA --> - <data type="i18n"> - <id>view_header</id> - <title/> - <init name="view_header">Single task view</init> - <component> - <name>divider</name> - </component> - </data> - <data type="text"> - <id>transition_id</id> - <title name="transition_id">Transition id - - - - - - Zvoľte nový filter - Aktualizovať zobrazenie s vybraným filtrom - Filter - Súčasný filter - Vybrať zobrazenie - Nastavenie - Asociované zobrazenie - Zobrazenie jednej úlohy - ID prechodu - - - Neue Filter auswählen - Filter - Aktueller Filter - Aktualisiere die Ansicht mit dem ausgewählten Filter - Wählen Sie einen Ansichtstyp - Einstellungen - zugehörige Ansicht - Einzelaufgabenansicht - Übergangs-ID - - - - initialize - 368 - 208 - - hourglass_empty - - - data_sync - 368 - 328 - - - - settings - 496 - 112 - - settings - - admin - - true - true - true - true - - - - form_title - 4 - grid - - view_header - - visible - - - 0 - 0 - 1 - 4 - - outline - - - - - view_dataGroup - 4 - grid - - transition_id - - editable - - - 0 - 0 - 1 - 4 - - outline - - - - - - initialized - 496 - 208 - - 0 - false - - - uninitialized - 240 - 208 - - 1 - false - - - a1 - read - initialized - settings - 1 - - - a2 - regular - uninitialized - initialize - 1 - - - a3 - regular - initialize - initialized - 1 - - \ No newline at end of file diff --git a/src/main/resources/petriNets/engine-processes/menu/tabbed_task_view_configuration.xml b/src/main/resources/petriNets/engine-processes/menu/tabbed_task_view_configuration.xml deleted file mode 100644 index 66caae1268f..00000000000 --- a/src/main/resources/petriNets/engine-processes/menu/tabbed_task_view_configuration.xml +++ /dev/null @@ -1,718 +0,0 @@ - - tabbed_task_view_configuration - TTV - Tabbed task view configuration - check_box_outline_blank - true - false - false - - system - - true - true - true - - - - admin - - true - true - true - - - - default - - false - false - true - - - - system - System - - - admin - Admin - - - - { - com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField filterAutocomplete, - com.netgrif.application.engine.petrinet.domain.dataset.TaskField previewTaskRef, - com.netgrif.application.engine.petrinet.domain.dataset.CaseField selectedFilterRef, - com.netgrif.application.engine.petrinet.domain.dataset.ButtonField updateBtn, - com.netgrif.application.engine.petrinet.domain.Transition trans - -> - if (filterAutocomplete.getOptions().containsKey(filterAutocomplete.value)) { - change previewTaskRef value { - return [findTask({it.caseId.eq(filterAutocomplete.value).and(it.transitionId.eq("view_filter"))}).stringId] - } - make updateBtn,editable on trans when { true } - } else { - change filterAutocomplete options { - def findAllPredicate = { filterCase -> !selectedFilterRef.value.contains(filterCase.stringId) - && filterCase.dataSet["filter_type"].value == "Task" } - def options = findFilters(filterAutocomplete.value != null ? filterAutocomplete.value : "") - .findAll(findAllPredicate) - .collectEntries({filterCase -> [filterCase.stringId, filterCase.title]}) - return options - } - change previewTaskRef value { [] } - make updateBtn,visible on trans when { true } - } - } - - - { - com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField toBeUpdated, - com.netgrif.application.engine.petrinet.domain.dataset.MultichoiceMapField valueSelector, - com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField optionsHolder - -> - def existingOptions = optionsHolder.options - def selectedValues = valueSelector.value - def newOptions = [:] - - if (selectedValues != null) { - existingOptions.each { key, value -> - if (selectedValues.contains(key)) { - newOptions.put(key, value) - } - } - } - - if (!newOptions.containsKey(toBeUpdated.value)) { - change toBeUpdated value { null } - } - - change toBeUpdated options { newOptions } - } - - - - - selected_filter_preview - - </data> - <data type="taskRef"> - <id>current_filter_preview</id> - <title/> - </data> - <data type="i18n"> - <id>filter_header</id> - <title/> - <init name="filter_header">Current filter</init> - <component> - <name>divider</name> - </component> - </data> - <data type="text"> - <id>new_filter_id</id> - <title/> - </data> - <data type="boolean" immediate="true"> - <id>contains_filter</id> - <title/> - <init>false</init> - </data> - <data type="enumeration_map"> - <id>filter_autocomplete_selection</id> - <title name="filter_autocomplete_selection">Select new filter - - autocomplete_dynamic - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - - update_filter - - <placeholder name="update_filter">Update view with selected filter</placeholder> - <component> - <name>raised</name> - </component> - <action trigger="set"> - trans: t.settings, - update_filter: f.update_filter, - contains_filter: f.contains_filter, - filter_case: f.filter_case, - filterAutocomplete: f.filter_autocomplete_selection; - - boolean containsFilter = filterAutocomplete.value != null && filterAutocomplete.value != "" - if (containsFilter) { - def filterCase = findCase({it._id.eq(filterAutocomplete.value)}) - if (filterCase.dataSet["filter_type"].value != "Task") { - throw new IllegalArgumentException("Filter is of wrong type. Only filter of Task type allowed.") - } - } - - change contains_filter value { containsFilter } - change filter_case value { [filterAutocomplete.value] } - change filterAutocomplete value { "" } - make update_filter,visible on trans when { true } - </action> - </data> - <data type="caseRef"> - <id>filter_case</id> - <title/> - <action trigger="set"> - trans: t.settings, - filterHeader: f.filter_header, - removeButton: f.remove_filter, - contains_filter: f.contains_filter, - mergeFilters: f.merge_filters, - filterTaskRef: f.current_filter_preview, - filterCaseRef: f.filter_case; - - if (filterCaseRef.value == null || filterCaseRef.value == []) { - make [mergeFilters, removeButton], hidden on trans when { true } - make filterHeader, hidden on trans when { true } - change filterTaskRef value { [] } - change contains_filter value { false } - return - } - - def filterCase = findCase({it._id.eq(filterCaseRef.value[0])}) - change filterTaskRef value { - return [findTask({it.caseId.eq(filterCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId] - } - - make [mergeFilters, removeButton], editable on trans when { true } - make filterHeader,visible on trans when { true } - change contains_filter value { true } - </action> - <allowedNets> - <allowedNet>filter</allowedNet> - </allowedNets> - </data> - <data type="button"> - <id>remove_filter</id> - <title/> - <placeholder name="remove_filter">Remove filter</placeholder> - <component> - <name>raised</name> - </component> - <action trigger="set"> - filterCase: f.filter_case; - - change filterCase value { [] } - </action> - </data> - <data type="boolean" immediate="true"> - <id>merge_filters</id> - <title name="merge_filters">Merge with base filter? - true - - - - - view_header - - <init name="view_header">Task view</init> - <component> - <name>divider</name> - </component> - </data> - <data type="enumeration_map" immediate="true"> - <id>view_search_type</id> - <title name="view_search_type">Search type for task view - - - - - - fulltext_advanced - - - headers_mode - Header mode - - - - - sort,edit - - headersMode: f.headers_mode, - defaultMode: f.headers_default_mode, - holder: f.headers_options_holder; - - updateOptionsBasedOnValue(defaultMode, headersMode, holder) - - - headersMode: f.headers_mode, - defaultMode: f.headers_default_mode, - holder: f.headers_options_holder; - - updateOptionsBasedOnValue(defaultMode, headersMode, holder) - - - - headers_default_mode - Default header mode - - - - - sort - - - headers_options_holder - - <options> - <option key="sort" name="sort">Sort</option> - <option key="edit" name="edit">Edit</option> - </options> - </data> - <data type="boolean" immediate="true"> - <id>is_header_mode_changeable</id> - <title name="is_header_mode_changeable">Can header mode be changed? - true - - - allow_header_table_mode - Allow table mode for headers? - true - - - use_default_headers - Use custom default headers? - true - - - default_headers - Set default headers - Example: "meta-title,meta-user" - - defaultHeaders: f.this; - - String trimmed = defaultHeaders.value?.replaceAll("\\s","") - if (defaultHeaders.value != trimmed) { - change defaultHeaders value { trimmed } - } - - - - show_more_menu - Show more menu for task item? - true - - - - - Zvoľte nový filter - Aktualizovať zobrazenie s vybraným filtrom - Skryté - Fulltext - Fulltext a rozšírené - Zoraďovanie - Vyhľadávanie - Upravovanie - Zjednotiť filter so základným filtrom? - Typ vyhľadávania úloh - Mód hlavičiek - Predvolený mód hlavičiek - Môže byť mód hlavičiek zmenený? - Povoliť tabuľkový mód pre hlavičky? - Použiť vlastné predvolené hlavičky? - Predvolené hlavičky - Napríklad: "meta-title,meta-user" - Zobrazovať menu pre úlohovú položku? - Nastavenie položky - Filter - Súčasný filter - Zobrazenie úloh - Všeobecné - Vymazať filter - - - Neue Filter auswählen - Versteckt - Einfacher Suchmodus - Sortieren - Suchen - Bearbeiten - Kopfzeilenmodus - Standardkopfzeilenmodus - Erlaube Änderung des Kopfzeilenmodus? - Erlaube Tabellenmodus? - Eigene Kopfzeilen verwenden? - Anzuzeigende Attributmenge auswählen - Beispiel: "meta-title,meta-user" - Filter - Aktueller Filter - Allgemein - Aktualisiere die Ansicht mit dem ausgewählten Filter - Einfacher und erweiterter Suchmodus - Mit dem Basisfilter kombinieren? - Suchmodus im Aufgabenansicht - "Erweiterte Optionen" Taste bei einzelnen Aufgaben anzeigen - Menüeintrageinstellungen - Aufgabenansicht - Filter entfernen - - - - initialize - 368 - 208 - - hourglass_empty - - - data_sync - 368 - 328 - - - - settings - 496 - 112 - - settings - - admin - - true - true - true - true - - - - form_title - 4 - grid - - view_header - - visible - - - 0 - 0 - 1 - 4 - - outline - - - - - filter_update - 4 - grid - Filter - - filter_autocomplete_selection - - editable - - - 0 - 0 - 1 - 3 - - outline - - - - update_filter - - visible - - - 3 - 0 - 1 - 1 - - standard - - - - selected_filter_preview - - visible - - - 0 - 1 - 1 - 4 - - standard - - - - - current_additional_filter - 4 - grid - - filter_header - - visible - - - 0 - 0 - 1 - 4 - - outline - - - - current_filter_preview - - visible - - - 0 - 1 - 1 - 4 - - standard - - - - merge_filters - - hidden - - - 0 - 2 - 1 - 1 - - standard - - - - remove_filter - - hidden - - - 1 - 2 - 1 - 1 - - standard - - - - - view_dataGroup - 4 - grid - - view_search_type - - editable - required - - - 0 - 0 - 1 - 3 - - outline - - - - show_more_menu - - editable - required - - - 3 - 0 - 1 - 1 - - outline - - - - - view_headers - 5 - grid - - is_header_mode_changeable - - editable - required - - trans: t.this, - isChangeable: f.is_header_mode_changeable, - mode: f.headers_mode, - defaultMode: f.headers_default_mode; - - make [mode, defaultMode], editable on trans when { isChangeable.value } - make [mode, defaultMode], required on trans when { isChangeable.value } - - make [mode, defaultMode], hidden on trans when { !isChangeable.value } - make [mode, defaultMode], optional on trans when { !isChangeable.value } - - - - 0 - 0 - 1 - 1 - 0 - - outline - - - - allow_header_table_mode - - editable - required - - - 1 - 0 - 1 - 1 - - outline - - - - headers_mode - - editable - required - - - 2 - 0 - 1 - 2 - - outline - - - - headers_default_mode - - editable - required - - - 4 - 0 - 1 - 1 - - outline - - - - use_default_headers - - editable - - trans: t.this, - use: f.use_default_headers, - headers: f.default_headers; - - make headers,editable on trans when { use.value } - make headers,visible on trans when { !use.value } - - - - 0 - 1 - 1 - 1 - 0 - - outline - - - - default_headers - - editable - - - 1 - 1 - 1 - 4 - 0 - - outline - - - - - - initialized - 496 - 208 - - 0 - false - - - uninitialized - 240 - 208 - - 1 - false - - - a1 - read - initialized - settings - 1 - - - a2 - regular - uninitialized - initialize - 1 - - - a3 - regular - initialize - initialized - 1 - - \ No newline at end of file diff --git a/src/main/resources/petriNets/engine-processes/menu/tabbed_ticket_view_configuration.xml b/src/main/resources/petriNets/engine-processes/menu/tabbed_ticket_view_configuration.xml index b68407bc78a..d306553a1b6 100644 --- a/src/main/resources/petriNets/engine-processes/menu/tabbed_ticket_view_configuration.xml +++ b/src/main/resources/petriNets/engine-processes/menu/tabbed_ticket_view_configuration.xml @@ -25,8 +25,6 @@ default - false - false true @@ -49,30 +47,10 @@ Admin - - { - com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField filterAutocomplete, - com.netgrif.application.engine.petrinet.domain.dataset.TaskField previewTaskRef, - com.netgrif.application.engine.petrinet.domain.dataset.CaseField selectedFilterRef, - com.netgrif.application.engine.petrinet.domain.dataset.ButtonField updateBtn, - com.netgrif.application.engine.petrinet.domain.Transition trans - -> - if (filterAutocomplete.getOptions().containsKey(filterAutocomplete.value)) { - change previewTaskRef value { - return [findTask({it.caseId.eq(filterAutocomplete.value).and(it.transitionId.eq("view_filter"))}).stringId] - } - make updateBtn,editable on trans when { true } - } else { - change filterAutocomplete options { - def findAllPredicate = { filterCase -> !selectedFilterRef.value.contains(filterCase.stringId) - && filterCase.dataSet["filter_type"].value == "Case" } - return findFilters(filterAutocomplete.value != null ? filterAutocomplete.value : "") - .findAll(findAllPredicate) - .collectEntries({filterCase -> [filterCase.stringId, filterCase.title]}) - } - change previewTaskRef value { [] } - make updateBtn,visible on trans when { true } - } + + { -> + def advancedContentFormField = useCase.getField("advanced_content_form") + change advancedContentFormField value { [useCase.tasks.find { taskPair -> taskPair.transition == "next_view_settings"}.task] } } @@ -89,114 +67,10 @@ } - - - selected_filter_preview - - </data> - <data type="taskRef"> - <id>current_filter_preview</id> - <title/> - </data> - <data type="i18n"> - <id>filter_header</id> - <title/> - <init name="filter_header">Current filter</init> - <component> - <name>divider</name> - </component> - </data> - <data type="text"> - <id>new_filter_id</id> - <title/> - </data> - <data type="boolean" immediate="true"> - <id>contains_filter</id> - <title/> - <init>false</init> - </data> - <data type="enumeration_map"> - <id>filter_autocomplete_selection</id> - <title name="filter_autocomplete_selection">Select new filter - - autocomplete_dynamic - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - trans: t.settings, - filterAutocomplete: f.this, - filter_case: f.filter_case, - update_filter: f.update_filter, - previewTaskRef: f.selected_filter_preview; - - updateFilterAutocompleteOptions(filterAutocomplete, previewTaskRef, filter_case, update_filter, trans) - - - - update_filter - - <placeholder name="update_filter">Update view with selected filter</placeholder> - <component> - <name>raised</name> - </component> - <action trigger="set"> - trans: t.settings, - update_filter: f.update_filter, - contains_filter: f.contains_filter, - filter_case: f.filter_case, - filterAutocomplete: f.filter_autocomplete_selection; - - boolean containsFilter = filterAutocomplete.value != null && filterAutocomplete.value != "" - if (containsFilter) { - def filterCase = findCase({it._id.eq(filterAutocomplete.value)}) - if (filterCase.dataSet["filter_type"].value != "Case") { - throw new IllegalArgumentException("Filter is of wrong type. Only filter of Case type allowed.") - } - } - - change contains_filter value { containsFilter } - change filter_case value { [filterAutocomplete.value] } - change filterAutocomplete value { "" } - make update_filter,visible on trans when { true } - </action> - </data> - <data type="caseRef"> - <id>filter_case</id> - <title/> - <action trigger="set"> - filterTaskRef: f.current_filter_preview, - contains_filter: f.contains_filter, - filterCaseRef: f.filter_case; - - if (filterCaseRef.value == null || filterCaseRef.value == []) { - change filterTaskRef value { [] } - change contains_filter value { false } - return - } - - def filterCase = findCase({it._id.eq(filterCaseRef.value[0])}) - change filterTaskRef value { - return [findTask({it.caseId.eq(filterCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId] - } - change contains_filter value { true } - </action> - <allowedNets> - <allowedNet>filter</allowedNet> - </allowedNets> - </data> - <!-- ASSOCIATED VIEW: this section can be removed if needed --> <data type="enumeration_map" immediate="true"> <id>view_configuration_type</id> - <title name="view_configuration_type">Pick view type + View type menuItemService.getAvailableViewsAsOptions(true, useCase.processIdentifier) @@ -212,46 +86,40 @@ view_configuration_id <allowedNets> - <allowedNet>tabbed_single_task_view_configuration</allowedNet> + <allowedNet>single_task_view_configuration</allowedNet> </allowedNets> </data> <data type="taskRef"> <id>view_configuration_form</id> <title/> </data> + <data type="taskRef"> + <id>view_configuration_all_data_form</id> + <title/> + </data> <!-- END OF ASSOCIATED VIEW --> <!-- VIEW CONFIGURATION DATA --> - <data type="i18n"> - <id>view_header</id> + <data type="taskRef"> + <id>advanced_content_form</id> <title/> - <init name="view_header">Ticket view</init> <component> - <name>divider</name> + <name>task-list</name> + <property key="headers">meta-title</property> </component> </data> <!-- END OF VIEW CONFIGURATION DATA --> <!-- I18NS --> <i18n locale="sk"> - <i18nString name="filter_autocomplete_selection">Zvoľte nový filter</i18nString> - <i18nString name="update_filter">Aktualizovať zobrazenie s vybraným filtrom</i18nString> - <i18nString name="filter_update_title">Filter</i18nString> - <i18nString name="filter_header">Súčasný filter</i18nString> - <i18nString name="view_configuration_type">Vybrať zobrazenie</i18nString> + <i18nString name="view_configuration_type">Zobrazenie</i18nString> <i18nString name="settings">Nastavenie</i18nString> - <i18nString name="associated_view">Asociované zobrazenie</i18nString> - <i18nString name="view_header">Tiketové zobrazenie</i18nString> + <i18nString name="next_view_settings">Ďalšie zobrazenie</i18nString> </i18n> <i18n locale="de"> - <i18nString name="filter_autocomplete_selection">Neue Filter auswählen</i18nString> - <i18nString name="filter_update_title">Filter</i18nString> - <i18nString name="filter_header">Aktueller Filter</i18nString> - <i18nString name="update_filter">Aktualisiere die Ansicht mit dem ausgewählten Filter</i18nString> - <i18nString name="view_configuration_type">Wählen Sie einen Ansichtstyp</i18nString> + <i18nString name="view_configuration_type">Der Ansichtstyp</i18nString> <i18nString name="settings">Einstellungen</i18nString> - <i18nString name="associated_view">zugehörige Ansicht</i18nString> - <i18nString name="view_header">Ticketansicht</i18nString> + <i18nString name="next_view_settings">Nächste Ansicht</i18nString> </i18n> <transition> @@ -260,12 +128,32 @@ <y>208</y> <label>initialize [await sync]</label> <icon>hourglass_empty</icon> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <event type="finish"> + <id>finish</id> + <actions phase="post"> + <action> + initializeAdvancedForm() + </action> + </actions> + </event> </transition> <transition> <id>data_sync</id> <x>368</x> <y>328</y> <label>Data sync</label> + <roleRef> + <id>system</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> </transition> <transition> <id>settings</id> @@ -277,39 +165,70 @@ <id>admin</id> <logic> <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> <view>true</view> - <cancel>true</cancel> - <assign>true</assign> </logic> </roleRef> <dataGroup> - <id>form_title</id> + <id>settings_0</id> <cols>4</cols> <layout>grid</layout> <dataRef> - <id>view_header</id> + <id>advanced_content_form</id> <logic> - <behavior>visible</behavior> + <behavior>editable</behavior> </logic> <layout> <x>0</x> <y>0</y> <rows>1</rows> <cols>4</cols> + <offset>0</offset> <template>material</template> <appearance>outline</appearance> </layout> </dataRef> </dataGroup> + <event type="assign"> + <id>assign_0</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + </transition> + <transition> + <id>next_view_settings</id> + <x>400</x> + <y>48</y> + <label name="next_view_settings">Next view</label> + <icon>queue_play_next</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> <dataGroup> <id>associated_view</id> <cols>4</cols> <layout>grid</layout> - <title name="associated_view">Associated view view_configuration_type - editable + visible 0 @@ -320,33 +239,6 @@ outline - - 0 - - - view_configuration_type: f.view_configuration_type, - view_configuration_form: f.view_configuration_form, - view_configuration_id: f.view_configuration_id; - - if (view_configuration_id.value != null && !view_configuration_id.value.isEmpty()) { - workflowService.deleteCase(view_configuration_id.value[0]) - } - - if (view_configuration_type.value == null || view_configuration_type.value == "") { - change view_configuration_id value { [] } - change view_configuration_form value { [] } - return - } - - def configurationCase = createCase(view_configuration_type.value + "_configuration") - def initTask = assignTask("initialize", configurationCase) - finishTask(initTask) - change view_configuration_id value { [configurationCase.stringId] } - configurationCase = workflowService.findOne(configurationCase.stringId) - change view_configuration_form value { [configurationCase.tasks.find { it.transition == "settings" }.task] } - - - view_configuration_form @@ -364,6 +256,52 @@
    + + assign + + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>all_menu_data</id> + <x>10</x> + <y>10</y> + <label>All menu data</label> + <roleRef> + <id>system</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>all_menu_data_0</id> + <layout>flow</layout> + <alignment>start</alignment> + <stretch>true</stretch> + <dataRef> + <id>view_configuration_type</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>view_configuration_all_data_form</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + </dataGroup> </transition> <place> <id>initialized</id> @@ -402,4 +340,11 @@ <destinationId>initialized</destinationId> <multiplicity>1</multiplicity> </arc> + <arc> + <id>a4</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>next_view_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> </document> \ No newline at end of file diff --git a/src/main/resources/petriNets/engine-processes/menu/task_view_configuration.xml b/src/main/resources/petriNets/engine-processes/menu/task_view_configuration.xml new file mode 100644 index 00000000000..d06fed2f1e6 --- /dev/null +++ b/src/main/resources/petriNets/engine-processes/menu/task_view_configuration.xml @@ -0,0 +1,861 @@ +<document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://petriflow.com/petriflow.schema.xsd"> + <id>task_view_configuration</id> + <initials>TTV</initials> + <title>Task view configuration + check_box_outline_blank + true + false + false + + system + + true + true + true + + + + admin + + true + true + true + + + + default + + true + + + + system + System + + + admin + Admin + + + + { -> + def advancedContentFormField = useCase.getField("advanced_content_form") + change advancedContentFormField value { [useCase.tasks.find { taskPair -> taskPair.transition == "filter_settings"}.task, + useCase.tasks.find { taskPair -> taskPair.transition == "header_settings"}.task] } + } + + + { + com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField toBeUpdated, + com.netgrif.application.engine.petrinet.domain.dataset.MultichoiceMapField valueSelector, + com.netgrif.application.engine.petrinet.domain.dataset.EnumerationMapField optionsHolder + -> + def existingOptions = optionsHolder.options + def selectedValues = valueSelector.value + def newOptions = [:] + + if (selectedValues != null) { + existingOptions.each { key, value -> + if (selectedValues.contains(key)) { + newOptions.put(key, value) + } + } + } + + if (!newOptions.containsKey(toBeUpdated.value)) { + change toBeUpdated value { null } + } + + change toBeUpdated options { newOptions } + } + + + + merge_filters + Merge with base filter if present? + true + + + task_filter + Filter + Use Elasticsearch string query + * + + + + + task_view_search_type + Search type for task view + + + + + + fulltext_advanced + + + task_headers_mode + Header mode + + + + + sort,edit + + headersMode: f.task_headers_mode, + defaultMode: f.task_headers_default_mode, + holder: f.headers_options_holder; + + updateOptionsBasedOnValue(defaultMode, headersMode, holder) + + + headersMode: f.task_headers_mode, + defaultMode: f.task_headers_default_mode, + holder: f.headers_options_holder; + + updateOptionsBasedOnValue(defaultMode, headersMode, holder) + + + + task_headers_default_mode + Default header mode + + + + + sort + + + headers_options_holder + + <options> + <option key="sort" name="sort">Sort</option> + <option key="edit" name="edit">Edit</option> + </options> + </data> + <data type="boolean" immediate="true"> + <id>task_is_header_mode_changeable</id> + <title name="task_is_header_mode_changeable">Can header mode be changed? + true + + + task_allow_header_table_mode + Allow table mode for headers? + true + + + use_task_default_headers + Use custom default headers? + true + + + task_default_headers + Set default headers + Example: "meta-title", "meta-user" + + + task_show_more_menu + Show more menu for task item? + true + + + advanced_content_form + + <component> + <name>task-list</name> + <property key="headers">meta-caseId,meta-title</property> + </component> + </data> + <data type="i18n"> + <id>task_empty_content_text</id> + <title name="task_empty_content_text">Empty content text + If empty, default text will be used + + + task_empty_content_icon + Empty content icon + If empty, default icon will be used + + 0 + + + icon: f.this, + iconPreview: f.task_empty_content_icon_preview; + + if (icon.value == "") { + change iconPreview value {"""]]>} + return + } + + change iconPreview value { + """]]> + icon.value + """]]> + } + + + + + + task_empty_content_icon_preview + Empty content icon preview + + htmltextarea + + + + task_allowed_nets + Allowed nets + + + task_all_allowed_nets + All allowed nets? + true + + + task_inherit_allowed_nets + Inherit allowed nets? + true + + + + + Skryté + Fulltext + Fulltext a rozšírené + Zoraďovanie + Vyhľadávanie + Upravovanie + Zjednotiť filter so základným filtrom ak existuje? + Typ vyhľadávania úloh + Mód hlavičiek + Predvolený mód hlavičiek + Môže byť mód hlavičiek zmenený? + Povoliť tabuľkový mód pre hlavičky? + Použiť vlastné predvolené hlavičky? + Predvolené hlavičky + Napríklad: "meta-title", "meta-user" + Zobrazovať menu pre úlohovú položku? + Nastavenie položky + Všeobecné + Text prázdneho obsahu + Ak je toto pole prázdne, bude použitý predvolený text + Ikona prázdneho obsahu + Ak je toto pole prázdne, bude použitá predvolená ikona + Náhľad ikony prázdneho obsahu + Povolené procesy + Povoliť všetky procesy? + Zdediť povolené procesy? + Filter + Použi Elasticsearch string query + Filter + Hlavičky + + + Versteckt + Einfacher Suchmodus + Sortieren + Suchen + Bearbeiten + Kopfzeilenmodus + Standardkopfzeilenmodus + Erlaube Änderung des Kopfzeilenmodus? + Erlaube Tabellenmodus? + Eigene Kopfzeilen verwenden? + Anzuzeigende Attributmenge auswählen + Beispiel: "meta-title", "meta-user" + Allgemein + Einfacher und erweiterter Suchmodus + Mit dem Basisfilter kombinieren, falls vorhanden? + Suchmodus im Aufgabenansicht + "Erweiterte Optionen" Taste bei einzelnen Aufgaben anzeigen + Menüeintrageinstellungen + Text für leeren Inhalt + Wenn dieses Feld leer ist, wird der Standardtext verwendet + Icon für leeren Inhalt + Wenn dieses Feld leer ist, wird das Standard-Icon verwendet + Vorschau des Icons für leeren Inhalt + Erlaubte Prozesse + Alle Prozesse erlauben? + Erlaubte Prozesse erben? + Filter + Elasticsearch String-Query verwenden + Filter + Kopfzeilen + + + + initialize + 368 + 208 + + hourglass_empty + + admin + + true + + + + finish + + + initializeAdvancedForm() + + + + + + data_sync + 368 + 328 + + + system + + true + + + + + settings + 496 + 112 + + settings + + admin + + true + + + + default + + true + + + + view_dataGroup + 3 + grid + + task_view_search_type + + editable + required + + + 0 + 0 + 1 + 1 + + outline + + + + task_show_more_menu + + editable + + + 1 + 0 + 1 + 1 + + outline + + + + task_empty_content_text + + editable + + + 0 + 1 + 1 + 1 + + outline + + + + task_empty_content_icon + + editable + + + 1 + 1 + 1 + 1 + + outline + + + + task_empty_content_icon_preview + + visible + + + 2 + 1 + 1 + 1 + + standard + + + + task_all_allowed_nets + + editable + + + 0 + 2 + 1 + 1 + + outline + + + + task_allowed_nets + + editable + + + 1 + 2 + 1 + 1 + + outline + + + + task_inherit_allowed_nets + + editable + + + 2 + 2 + 1 + 1 + + outline + + + + advanced_content_form + + editable + + + 0 + 3 + 1 + 3 + + outline + + + + + assign_0 + + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + </transition> + <transition> + <id>filter_settings</id> + <x>400</x> + <y>48</y> + <label name="filter_settings">Filter</label> + <icon>filter_alt</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>filter_update</id> + <cols>4</cols> + <layout>grid</layout> + <dataRef> + <id>task_filter</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>0</y> + <rows>1</rows> + <cols>4</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>merge_filters</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <template>material</template> + <appearance>standard</appearance> + </layout> + </dataRef> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>header_settings</id> + <x>592</x> + <y>48</y> + <label name="header_settings">Header</label> + <icon>view_column</icon> + <assignPolicy>auto</assignPolicy> + <roleRef> + <id>admin</id> + <logic> + <perform>true</perform> + </logic> + </roleRef> + <roleRef> + <id>default</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>view_headers</id> + <cols>3</cols> + <layout>grid</layout> + <dataRef> + <id>task_is_header_mode_changeable</id> + <logic> + <behavior>editable</behavior> + <action trigger="set"> + trans: t.this, + isChangeable: f.task_is_header_mode_changeable, + mode: f.task_headers_mode, + defaultMode: f.task_headers_default_mode; + + make [mode, defaultMode], editable on trans when { isChangeable.value } + make [mode, defaultMode], required on trans when { isChangeable.value } + + make [mode, defaultMode], hidden on trans when { !isChangeable.value } + make [mode, defaultMode], optional on trans when { !isChangeable.value } + </action> + </logic> + <layout> + <x>0</x> + <y>0</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>use_task_default_headers</id> + <logic> + <behavior>editable</behavior> + <action trigger="set"> + trans: t.this, + use: f.use_task_default_headers, + headers: f.task_default_headers; + + make headers,editable on trans when { use.value } + make headers,visible on trans when { !use.value } + </action> + </logic> + <layout> + <x>1</x> + <y>0</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>task_default_headers</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>2</x> + <y>0</y> + <rows>1</rows> + <cols>1</cols> + <offset>0</offset> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>task_allow_header_table_mode</id> + <logic> + <behavior>editable</behavior> + </logic> + <layout> + <x>0</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>task_headers_mode</id> + <logic> + <behavior>editable</behavior> + <behavior>required</behavior> + </logic> + <layout> + <x>1</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + <dataRef> + <id>task_headers_default_mode</id> + <logic> + <behavior>editable</behavior> + <behavior>required</behavior> + </logic> + <layout> + <x>2</x> + <y>1</y> + <rows>1</rows> + <cols>1</cols> + <template>material</template> + <appearance>outline</appearance> + </layout> + </dataRef> + </dataGroup> + <event type="assign"> + <id>assign</id> + <title/> + </event> + <event type="cancel"> + <id>cancel</id> + <title/> + </event> + <event type="finish"> + <id>finish_0</id> + <title/> + </event> + <event type="delegate"> + <id>delegate</id> + <title/> + </event> + </transition> + <transition> + <id>all_menu_data</id> + <x>10</x> + <y>10</y> + <label>All menu data</label> + <roleRef> + <id>system</id> + <logic> + <view>true</view> + </logic> + </roleRef> + <dataGroup> + <id>all_menu_data_0</id> + <layout>flow</layout> + <alignment>start</alignment> + <stretch>true</stretch> + <dataRef> + <id>task_filter</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>merge_filters</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_view_search_type</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_show_more_menu</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_empty_content_text</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_empty_content_icon</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_empty_content_icon_preview</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_all_allowed_nets</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_allowed_nets</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_inherit_allowed_nets</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_is_header_mode_changeable</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_allow_header_table_mode</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_headers_mode</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_headers_default_mode</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>use_task_default_headers</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_default_headers</id> + <logic> + <behavior>visible</behavior> + </logic> + </dataRef> + </dataGroup> + </transition> + <place> + <id>initialized</id> + <x>496</x> + <y>208</y> + <label>initialized</label> + <tokens>0</tokens> + <static>false</static> + </place> + <place> + <id>uninitialized</id> + <x>240</x> + <y>208</y> + <label>uninitialized</label> + <tokens>1</tokens> + <static>false</static> + </place> + <arc> + <id>a1</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a2</id> + <type>regular</type> + <sourceId>uninitialized</sourceId> + <destinationId>initialize</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a3</id> + <type>regular</type> + <sourceId>initialize</sourceId> + <destinationId>initialized</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a4</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>filter_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> + <arc> + <id>a5</id> + <type>read</type> + <sourceId>initialized</sourceId> + <destinationId>header_settings</destinationId> + <multiplicity>1</multiplicity> + </arc> +</document> \ No newline at end of file diff --git a/src/main/resources/petriNets/engine-processes/org_group.xml b/src/main/resources/petriNets/engine-processes/org_group.xml index b23102b4812..426eae220d3 100644 --- a/src/main/resources/petriNets/engine-processes/org_group.xml +++ b/src/main/resources/petriNets/engine-processes/org_group.xml @@ -12,16 +12,6 @@ <!-- PROCESS ROLE REFS --> <!-- PROCESS USER REFS --> <!-- FUNCTIONS --> - <function scope="process" name="updateAvailableEntries"> - { - com.netgrif.application.engine.workflow.domain.Case useCase -> - - def cases = findCasesElastic( - "processIdentifier:\"preference_filter_item\" AND dataSet.parentId.textValue.keyword:\"$useCase.stringId\"" as String, - org.springframework.data.domain.PageRequest.of(0, 1000)) - change availableEntries options { return menuImportExportService.createAvailableEntriesChoices(cases) } - } - </function> <role> <id>system</id> <title>System @@ -122,11 +112,6 @@ update_available_entries_btn Update entries - - availableEntries: f.available_export_entries; - - updateAvailableEntries(useCase) - clear_menu_selection_btn @@ -265,8 +250,6 @@ finishTask(initTask) workflowService.save(useCase) - - updateAvailableEntries(useCase)
    @@ -384,30 +367,6 @@
    - - 1 - - - availableEntries: f.available_export_entries; - - defaultFilters = findDefaultFilters() - - defaultFilters.forEach { filterCase -> - def optionCase = createCase("preference_filter_item", filterCase.title + " filter preference") - - def initTask = findTask({it.transitionId.eq("init").and(it.caseId.eq(optionCase.stringId))}) - assignTask(initTask) - setData(initTask, [ - "filter_case": ["type":"caseRef", "value": [filterCase.stringId], "allowedNets":["filter"]], - "parentId": ["type":"text", "value":useCase.stringId], "menu_identifier": ["type":"text", value:"defaultMenu"] - ]) - finishTask(initTask) - } - - updateAvailableEntries(useCase) - - - 6 diff --git a/src/main/resources/petriNets/engine-processes/preference_filter_item.xml b/src/main/resources/petriNets/engine-processes/preference_filter_item.xml deleted file mode 100644 index 2e12b82a51d..00000000000 --- a/src/main/resources/petriNets/engine-processes/preference_filter_item.xml +++ /dev/null @@ -1,983 +0,0 @@ - - - preference_filter_item - PFI - Preference filter item - list - true - false - - - - - - - menu_identifier - Identifier of menu which is this menu entry part of. - default - - - entry_name - - - - entry_default_name - Menu item title - - - entry_marker - - - - move_option_up - - Up - - parentId: f.parentId; - - if (!task.isPresent()) { - return; - } - - def parentCase = findCase({it._id.eq(new org.bson.types.ObjectId(parentId.value))}); - - def previousTaskRefValue = parentCase.dataSet.get("filter_tasks").value - - def currentIndex = previousTaskRefValue.findIndexOf({ id -> id == task.get().stringId}) - - if (currentIndex != 0) { - previousTaskRefValue.remove(currentIndex) - previousTaskRefValue.add(currentIndex - 1, task.get().stringId) - - def parentTask = findTask({it.caseId.eq(parentId.value).and(it.transitionId.eq("navigationMenuConfig"))}) - - setDataWithPropagation(parentTask, [ - "filter_tasks": ["type": "taskRef", "value": previousTaskRefValue] - ]) - } - - - - move_option_down - - Down - - parentId: f.parentId; - - if (!task.isPresent()) { - return; - } - - def parentCase = findCase({it._id.eq(new org.bson.types.ObjectId(parentId.value))}); - - def previousTaskRefValue = parentCase.dataSet.get("filter_tasks").value - - def currentIndex = previousTaskRefValue.findIndexOf({ id -> id == task.get().stringId}) - - if (currentIndex != previousTaskRefValue.size() - 1) { - previousTaskRefValue.remove(currentIndex) - previousTaskRefValue.add(currentIndex + 1, task.get().stringId) - - def parentTask = findTask({it.caseId.eq(parentId.value).and(it.transitionId.eq("navigationMenuConfig"))}) - - setDataWithPropagation(parentTask, [ - "filter_tasks": ["type": "taskRef", "value": previousTaskRefValue] - ]) - } - - - - remove_option - - Remove - - parentId: f.parentId, - filterCase: f.filter_case; - - if (!task.isPresent()) { - return; - } - - def parentCase = findCase({it._id.eq(new org.bson.types.ObjectId(parentId.value))}); - - - def previousTaskRefValue = parentCase.dataSet.get("filter_tasks").value - - def currentIndex = previousTaskRefValue.findIndexOf({ id -> id == task.get().stringId}) - - previousTaskRefValue.remove(currentIndex) - - - def previousCaseRefValue = parentCase.dataSet.get("referenced_filters").value - - currentIndex = previousCaseRefValue.findIndexOf({id -> id == filterCase.value[0]}) - - previousCaseRefValue.remove(currentIndex) - - - def parentTask = findTask({it.caseId.eq(parentId.value).and(it.transitionId.eq("navigationMenuConfig"))}) - - setDataWithPropagation(parentTask, [ - "filter_tasks": ["type": "taskRef", "value": previousTaskRefValue], - "referenced_filters": ["type": "caseRef", "value": previousCaseRefValue], - ]) - async.run { - workflowService.deleteCase(useCase.stringId) - } - - - - filter_preview - - - - filter_case - - - filter - - - - parentId - - - - use_icon - Display menu icon? - true - - - icon_preview - Menu icon preview - - htmltextarea - - - - - icon_name - Menu icon identifier - Material icon identifier. List of icons with identifiers is available online. - - iconIdentifier: f.this, - iconPreview: f.icon_preview; - - if (iconIdentifier.value == "") { - change iconPreview value {"""]]>} - return; - } - - change iconPreview value { - """]]> + iconIdentifier.value + """]]> - } - - - - add_allowed_roles - - Allow view for roles - - allowedRoles: f.allowed_roles, - processesAvailable: f.processes_available, - rolesAvailable: f.roles_available; - - change allowedRoles options {return configurableMenuService.addSelectedRoles(allowedRoles, processesAvailable, rolesAvailable)} - - change rolesAvailable value {[]} - change rolesAvailable options {[:]} - change processesAvailable value {null} - - - - remove_allowed_roles - - Remove from allowed roles - - allowedRoles: f.allowed_roles, - processesAvailable: f.processes_available, - rolesAvailable: f.roles_available; - - change allowedRoles options {return configurableMenuService.removeSelectedRoles(allowedRoles)} - - change allowedRoles value {[]} - change rolesAvailable value {[]} - change rolesAvailable options {[:]} - change processesAvailable value {null} - - - - add_banned_roles - - Ban view for roles - - bannedRoles: f.banned_roles, - processesAvailable: f.processes_available, - rolesAvailable: f.roles_available; - - change bannedRoles options {return configurableMenuService.addSelectedRoles(bannedRoles, processesAvailable, rolesAvailable)} - - change rolesAvailable value {[]} - change rolesAvailable options {[:]} - change processesAvailable value {null} - - - - remove_banned_roles - - Remove from banned roles - - bannedRoles: f.banned_roles, - processesAvailable: f.processes_available, - rolesAvailable: f.roles_available; - - change bannedRoles options {return configurableMenuService.removeSelectedRoles(bannedRoles)} - - change bannedRoles value {[]} - change rolesAvailable value {[]} - change rolesAvailable options {[:]} - change processesAvailable value {null} - - - - processes_available - Your processes - Select a process containing roles you wish to add to allowed or banned roles lists. - - processes: f.this; - - change processes options {return configurableMenuService.getNetsByAuthorAsMapOptions(loggedUser(), org.springframework.context.i18n.LocaleContextHolder.locale)} - - - processes: f.this, - allowedRoles: f.allowed_roles, - bannedRoles: f.banned_roles, - rolesAvailable: f.roles_available; - - change rolesAvailable options {return configurableMenuService.getAvailableRolesFromNet(processes, allowedRoles, bannedRoles)} - change rolesAvailable value {[]} - - - - roles_available - Available roles from selected process - - - allowed_roles - Allowed roles - List of roles allowed to view this menu entry. - - - banned_roles - Banned roles - List of roles not allowed to view this menu entry. - - - new_filter_id - - </data> - <data type="text" immediate="true"> - <id>menu_item_identifier</id> - <title>Identifikátor (Filter API) - - - create_case_button_title - "New case" button title - - - create_case_button_icon_preview - Menu icon preview - - htmltextarea - - - - create_case_button_icon - "New case" button icon identifier - - create_case_button_icon_preview: f.create_case_button_icon_preview, - create_case_button_icon: f.create_case_button_icon; - - - if (create_case_button_icon.value == "") { - change create_case_button_icon_preview value {"""]]>} - return; - } - - change create_case_button_icon_preview value { - """]]> + create_case_button_icon.value + """]]> - } - - - - - default_headers - Set default headers - - - - allowed_nets - Allowed nets - - - - - - - - - - - - - - - - - - - - - - Názov položky menu - Posunúť nahor - Posunúť nadol - Odstrániť - Zobrazovať ikonu? - Náhľad ikony - Identifikátor ikony - Identifikátor Material ikony. Zoznam ikon s identifikátormi je dostupný online. - Pridaj k povoleným roliam - Odstráň z povolených rolí - Pridaj k zakázaným roliam - Odstráň zo zakázaných rolí - Vaše procesy - Vyberte proces obsahujúci roly ktoré chcete pridať do zoznamu povolených alebo zakázaných rolí. - Dostupné roly - Povolené roly - Zoznam rolí ktoré budú upravovaný menu záznam vidieť. - Zakázané roly - Zoznam rolí pre ktoré bude upravovaný menu záznam skrytý. - Názov tlačidla "Nová inštancia" - Identifikátor ikony tlačidla "Nová inštancia" - Náhľad ikony - Predvolené hlavičky - - - Menüpunkttitel - nach oben - nach unten - entfernen - Menüikone anzeigen - Ikonevorschau - Ikone ID - Material Ikone ID. Liste den Ikonen mit IDs ist online verfügbar. - Zu zulässigen Rollen hinzufügen - Aus zulässigen Rollen entfernen - Zu verbotenen Rollen hinzufügen - Aus verbotenen Rollen entfernen - Ihre Prozesse - Wählen Sie einen Prozess mit Rollen aus, die Sie zu Listen mit zulässigen oder verbotenen Rollen hinzufügen möchten. - Verfügbare Rollen - Zulässige Rollen - Liste der Rollen, die diesen Menüeintrag anzeigen dürfen. - Verbotene Rollen - Liste der Rollen, die diesen Menüeintrag nicht anzeigen dürfen. - Schaltflächentitel "Neuer Fall" - Ikone ID - Ikonevorschau - Anzuzeigende Attributmenge auswählen - - - - init - 420 - 260 - - 0 - - - - filter_case - - forbidden - - - 1 - 0 - 1 - 2 - - - - - filterTaskRef: f.filter_preview, - filterCaseRef: f.filter_case, - entryDefaultName: f.entry_default_name, - entryName: f.entry_name, - icon: f.icon_name; - - def filterCase = findCase({it._id.eq(filterCaseRef.value[0])}) - - change entryDefaultName value {return filterCase.title} - - change entryName value {return filterCase.dataSet["i18n_filter_name"].value} - - change filterTaskRef value {return [findTask({it.caseId.eq(filterCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId]} - - change icon value {filterCase.icon} - - - - - parentId - - editable - - - - icon_name - - editable - - - - - view - 660 - 260 - - 5 - 0 - - - - DataGroup_0 - - grid - - entry_default_name - - editable - - entryName: f.entry_name, - filterTask: f.filter_preview, - filterCaseRef: f.filter_case, - entryDefaultName: f.entry_default_name; - - def filterCase = findCase({it._id.eq(new org.bson.types.ObjectId(filterCaseRef.value[0]))}) - filterCase.setTitle(entryDefaultName.value) - workflowService.save(filterCase) - def filterTask = findTask({ it._id.eq(filterTask.value[0])}) - setData(filterTask, [ - "new_title": ["type":"text", "value": entryDefaultName.value] - ]) - - change entryName value {return new com.netgrif.application.engine.petrinet.domain.I18nString(entryDefaultName.value)} - - - - 0 - 0 - 1 - 2 - 0 - - outline - - - - move_option_up - - editable - - - 2 - 0 - 1 - 1 - 0 - - fill - - - - move_option_down - - editable - - - 3 - 0 - 1 - 1 - 0 - - - - - remove_option - - editable - - - 4 - 0 - 1 - 1 - 0 - - - - - processes_available - - editable - - - 0 - 1 - 2 - 1 - 0 - - outline - - - - roles_available - - editable - - - 1 - 1 - 2 - 1 - 0 - - outline - - - - add_allowed_roles - - editable - - - 2 - 1 - 1 - 1 - 0 - - - - - allowed_roles - - editable - - - 3 - 1 - 1 - 1 - 0 - - outline - - - - remove_allowed_roles - - editable - - - 4 - 1 - 1 - 1 - 0 - - - - - add_banned_roles - - editable - - - 2 - 2 - 1 - 1 - 0 - - - - - banned_roles - - editable - - - 3 - 2 - 1 - 1 - 0 - - outline - - - - remove_banned_roles - - editable - - - 4 - 2 - 1 - 1 - 0 - - - - - use_icon - - editable - - - 0 - 3 - 1 - 1 - 0 - - - - 0 - - - trans: t.this, - iconPreview: f.icon_preview, - iconName: f.icon_name, - useIcon: f.use_icon; - - make iconPreview,visible on trans when {useIcon.value} - make iconName,editable on trans when {useIcon.value} - - make iconPreview,hidden on trans when {!useIcon.value} - make iconName,hidden on trans when {!useIcon.value} - - - - - - icon_preview - - visible - - - 1 - 3 - 1 - 1 - 0 - - - - icon_name - - editable - - iconIdentifier: f.icon_name, - filterCaseId: f.filter_case; - - def filterCase = findCase({it._id.eq(new org.bson.types.ObjectId(filterCaseId.value[0]))}) - filterCase.setIcon(iconIdentifier.value) - workflowService.save(filterCase) - - - - 2 - 3 - 1 - 2 - 0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - filter_preview - - editable - - - 0 - 3 - 1 - 5 - 0 - - outline - - - - entry_marker - - hidden - - - 0 - 4 - 1 - 1 - 0 - - - - - - entry_name - - hidden - - - 1 - 4 - 1 - 1 - 0 - - - - - - create_case_button_title - - editable - - - 0 - 5 - 1 - 2 - 0 - - outline - - - - create_case_button_icon_preview - - visible - - - 2 - 5 - 1 - 1 - 0 - - outline - - - - create_case_button_icon - - editable - - - 3 - 5 - 1 - 2 - 0 - - outline - - - - default_headers - - editable - - - 0 - 6 - 1 - 4 - 0 - - outline - - - - - - - change_filter - 420 - 350 - - - - new_filter_id - - editable - required - - - set_event_0 - - - new_filter_id: f.new_filter_id, - filterTaskRef: f.filter_preview, - filterCaseRef: f.filter_case, - entryDefaultName: f.entry_default_name, - entryName: f.entry_name, - icon: f.icon_name; - - change filterCaseRef value { [new_filter_id.value] } - def filterCase = findCase({it._id.eq(filterCaseRef.value[0])}) - - change entryDefaultName value {return filterCase.title} - - change entryName value {return filterCase.dataSet["i18n_filter_name"].value} - - change filterTaskRef value {return [findTask({it.caseId.eq(filterCase.stringId).and(it.transitionId.eq("view_filter"))}).stringId]} - - change icon value {filterCase.icon} - - - - - - - - p1 - 300 - 260 - - 1 - false - - - p2 - 540 - 260 - - 0 - false - - - - a4 - regular - p1 - init - 1 - - - a5 - regular - init - p2 - 1 - - - a6 - read - p2 - view - 1 - - - a7 - read - p2 - change_filter - 1 - - diff --git a/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy b/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy index db7992527bc..9d7e0019fc1 100644 --- a/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy +++ b/src/test/groovy/com/netgrif/application/engine/TestHelper.groovy @@ -3,6 +3,7 @@ package com.netgrif.application.engine import com.netgrif.application.engine.auth.domain.repositories.UserRepository import com.netgrif.application.engine.elastic.domain.ElasticCaseRepository import com.netgrif.application.engine.elastic.domain.ElasticTaskRepository +import com.netgrif.application.engine.menu.service.interfaces.IMenuItemService import com.netgrif.application.engine.petrinet.domain.repository.UriNodeRepository import com.netgrif.application.engine.petrinet.domain.roles.ProcessRoleRepository import com.netgrif.application.engine.petrinet.service.ProcessRoleService @@ -43,7 +44,7 @@ class TestHelper { @Autowired private IFieldActionsCacheService actionsCacheService @Autowired - private FilterRunner filterRunner + private MenuRunner filterRunner @Autowired private FinisherRunner finisherRunner @Autowired @@ -52,6 +53,10 @@ class TestHelper { private UriRunner uriRunner @Autowired private IPetriNetService petriNetService + @Autowired + private IMenuItemService menuItemService + @Autowired + private MongoDbRunner mongoDbRunner void truncateDbs() { template.db.drop() @@ -66,6 +71,7 @@ class TestHelper { actionsCacheService.clearNamespaceFunctionCache() petriNetService.evictAllCaches() + mongoDbRunner.run() defaultRoleRunner.run() anonymousRoleRunner.run() systemUserRunner.run() @@ -75,5 +81,6 @@ class TestHelper { impersonationRunner.run() superCreator.run() finisherRunner.run() + menuItemService.ensureDatabaseIndexes() } } \ No newline at end of file diff --git a/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy b/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy index 4900ac8595b..671838619c0 100644 --- a/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy +++ b/src/test/groovy/com/netgrif/application/engine/action/ActionDelegateTest.groovy @@ -8,7 +8,7 @@ import com.netgrif.application.engine.auth.service.interfaces.IUserService import com.netgrif.application.engine.auth.web.requestbodies.NewUserRequest import com.netgrif.application.engine.configuration.PublicViewProperties import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate -import com.netgrif.application.engine.workflow.service.interfaces.IFilterImportExportService + import com.netgrif.application.engine.workflow.web.responsebodies.MessageResource import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled @@ -34,9 +34,6 @@ class ActionDelegateTest { @Autowired private ActionDelegate actionDelegate - @Autowired - private IFilterImportExportService importExportService - @Autowired private IUserService userService @@ -48,14 +45,6 @@ class ActionDelegateTest { testHelper.truncateDbs() } - @Test - @Disabled("Context user") - void importFiltersTest(){ - List actionDelegateList = actionDelegate.importFilters() - List importedTasksIds = importExportService.importFilters() - assert actionDelegateList.size() == importedTasksIds.size() - } - @Test void inviteUser(){ GreenMail smtpServer = new GreenMail(new ServerSetup(2525, null, "smtp")) diff --git a/src/test/groovy/com/netgrif/application/engine/action/FilterApiTest.groovy b/src/test/groovy/com/netgrif/application/engine/action/FilterApiTest.groovy deleted file mode 100644 index fca6c5d1fbe..00000000000 --- a/src/test/groovy/com/netgrif/application/engine/action/FilterApiTest.groovy +++ /dev/null @@ -1,184 +0,0 @@ -package com.netgrif.application.engine.action - - -import com.netgrif.application.engine.TestHelper -import com.netgrif.application.engine.auth.service.interfaces.IUserService -import com.netgrif.application.engine.orgstructure.groups.interfaces.INextGroupService -import com.netgrif.application.engine.petrinet.domain.UriContentType -import com.netgrif.application.engine.petrinet.domain.dataset.logic.action.ActionDelegate -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService -import com.netgrif.application.engine.startup.FilterRunner -import com.netgrif.application.engine.startup.ImportHelper -import com.netgrif.application.engine.workflow.domain.Case -import com.netgrif.application.engine.workflow.domain.QCase -import com.netgrif.application.engine.workflow.service.interfaces.IDataService -import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService -import org.bson.types.ObjectId -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.junit.jupiter.SpringExtension - -@Disabled -@SpringBootTest -@ActiveProfiles(["test"]) -@ExtendWith(SpringExtension.class) -class FilterApiTest { - - @Autowired - private TestHelper testHelper - - @Autowired - private ImportHelper helper - - @Autowired - private FilterRunner filterRunner - - @Autowired - private IUserService userService - - @Autowired - private IWorkflowService workflowService - - @Autowired - private IDataService dataService - - @Autowired - private IUriService uriService - - @Autowired - private INextGroupService nextGroupService - - @BeforeEach - void before() { - testHelper.truncateDbs() - helper.createNet("filter_api_test.xml") - } - - @Test - @Disabled("Fix") - void testCreateFilterAndMenu() { - Case caze = createMenuItem() - Case item = getMenuItem(caze) - Case filter = getFilter(caze) - - Case defGroup = nextGroupService.findDefaultGroup() - - assert item.uriNodeId == uriService.findByUri("netgrif/test").id - assert item.dataSet["icon_name"].value == "device_hub" - assert item.dataSet["entry_name"].value.toString() == "FILTER" - assert item.dataSet["menu_item_identifier"].value.toString() == "new_menu_item" - assert item.dataSet["parentId"].value.toString() == defGroup.stringId - - assert filter.dataSet["filter"].filterMetadata["filterType"] == "Case" - assert filter.dataSet["filter"].allowedNets == ["filter", "preference_filter_item"] - assert filter.dataSet["filter"].value == "processIdentifier:filter OR processIdentifier:preference_filter_item" - assert filter.dataSet["filter_type"].value == "Case" - - List taskIds = (defGroup.dataSet[ActionDelegate.ORG_GROUP_FIELD_FILTER_TASKS].value ?: []) as List - assert taskIds.contains(item.tasks.find { it.transition == "view" }.task) - } - - - @Test - @Disabled("Fix NullPointer") - void testChangeFilterAndMenu() { - Case caze = createMenuItem() - def newUri = uriService.getOrCreate("netgrif/test_new", UriContentType.DEFAULT) - caze = setData(caze, [ - "uri": newUri.uriPath, - "title": "CHANGED FILTER", - "allowed_nets": "filter", - "query": "processIdentifier:filter", - "type": "Case", - "icon": "", - "change_filter_and_menu": "0" - ]) - Case item = getMenuItem(caze) - Case filter = getFilter(caze) - - assert item.dataSet["icon_name"].value == "" - assert item.dataSet["entry_name"].value.toString() == "CHANGED FILTER" - assert item.dataSet["allowed_roles"].options.entrySet()[0].key.contains("role_2") - assert item.uriNodeId == newUri.id - - assert filter.dataSet["filter"].allowedNets == ["filter"] - assert filter.dataSet["filter"].filterMetadata["defaultSearchCategories"] == false - assert filter.dataSet["filter"].value == "processIdentifier:filter" - } - - @Test - @Disabled("Fix") - void testDeleteItemAndFilter() { - Case caze = createMenuItem() - - Case item = getMenuItem(caze) - Case filter = getFilter(caze) - caze = setData(caze, [ - "delete_filter_and_menu": "0" - ]) - - Case defGroup = nextGroupService.findDefaultGroup() - List taskIds = (defGroup.dataSet[ActionDelegate.ORG_GROUP_FIELD_FILTER_TASKS].value ?: []) as List - assert !taskIds - - Thread.sleep(10000); - - assert workflowService.searchOne(QCase.case$._id.eq(new ObjectId(item.stringId))) == null - assert workflowService.searchOne(QCase.case$._id.eq(new ObjectId(filter.stringId))) == null - } - - - @Test - @Disabled("Fix") - void testFindFilter() { - Case caze = createMenuItem() - Case filter = getFilter(caze) - - caze = setData(caze, [ - "find_filter": "0" - ]) - - assert caze.dataSet["found_filter"].value == filter.stringId - } - - Case createMenuItem() { - Case caze = getCase() - caze = setData(caze, [ - "uri": "netgrif/test", - "title": "FILTER", - "allowed_nets": "filter,preference_filter_item", - "query": "processIdentifier:filter OR processIdentifier:preference_filter_item", - "type": "Case", - "group": null, - "identifier": "new_menu_item", - "icon": "device_hub", - "create_filter_and_menu": "0" - ]) - return caze - } - - Case getCase() { - return workflowService.searchOne(QCase.case$.processIdentifier.eq("netgrif/test/filter_api_test")) - } - - Case getMenuItem(Case caze) { - return workflowService.findOne(caze.dataSet["menu_stringId"].value as String) - } - - Case getFilter(Case caze) { - return workflowService.findOne(caze.dataSet["filter_stringId"].value as String) - } - - def setData(Case caze, Map dataSet) { - dataService.setData(caze.tasks[0].task, ImportHelper.populateDataset(dataSet.collectEntries { - [(it.key): (["value": it.value, "type": "text"])] - })) - return workflowService.findOne(caze.stringId) - } - -} diff --git a/src/test/groovy/com/netgrif/application/engine/action/MenuItemApiTest.groovy b/src/test/groovy/com/netgrif/application/engine/action/MenuItemApiTest.groovy deleted file mode 100644 index e3ae062e5e0..00000000000 --- a/src/test/groovy/com/netgrif/application/engine/action/MenuItemApiTest.groovy +++ /dev/null @@ -1,397 +0,0 @@ -package com.netgrif.application.engine.action - -import com.netgrif.application.engine.TestHelper -import com.netgrif.application.engine.auth.service.interfaces.IUserService -import com.netgrif.application.engine.elastic.service.interfaces.IElasticCaseService -import com.netgrif.application.engine.elastic.web.requestbodies.CaseSearchRequest -import com.netgrif.application.engine.menu.domain.MenuItemConstants -import com.netgrif.application.engine.menu.domain.MenuItemView -import com.netgrif.application.engine.menu.domain.configurations.TabbedCaseViewConstants -import com.netgrif.application.engine.menu.domain.configurations.TabbedTaskViewConstants -import com.netgrif.application.engine.menu.utils.MenuItemUtils -import com.netgrif.application.engine.orgstructure.groups.interfaces.INextGroupService -import com.netgrif.application.engine.petrinet.domain.I18nString -import com.netgrif.application.engine.petrinet.domain.UriContentType -import com.netgrif.application.engine.petrinet.domain.UriNode -import com.netgrif.application.engine.petrinet.service.interfaces.IUriService -import com.netgrif.application.engine.startup.FilterRunner -import com.netgrif.application.engine.startup.ImportHelper -import com.netgrif.application.engine.workflow.domain.Case -import com.netgrif.application.engine.workflow.domain.QCase -import com.netgrif.application.engine.workflow.service.interfaces.IDataService -import com.netgrif.application.engine.workflow.service.interfaces.ITaskService -import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.context.i18n.LocaleContextHolder -import org.springframework.data.domain.PageRequest -import org.springframework.data.domain.Pageable -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.junit.jupiter.SpringExtension - -import static org.junit.jupiter.api.Assertions.assertThrows - -@SpringBootTest -@ActiveProfiles(["test"]) -@ExtendWith(SpringExtension.class) -class MenuItemApiTest { - - @Autowired - private TestHelper testHelper - - @Autowired - private ImportHelper helper - - @Autowired - private FilterRunner filterRunner - - @Autowired - private IUserService userService - - @Autowired - private IWorkflowService workflowService - - @Autowired - private IDataService dataService - - @Autowired - private IUriService uriService - - @Autowired - private INextGroupService nextGroupService - - @Autowired - private IElasticCaseService elasticCaseService - - @Autowired - private ITaskService taskService - - @BeforeEach - void before() { - testHelper.truncateDbs() - helper.createNet("filter_api_test.xml") - } - - @Test - void testCreateFilterAndMenuItems() { - Case caze = createMenuItem() - Case item = getMenuItem(caze) - Case filter = getFilter(caze) - - Thread.sleep(4000) - UriNode leafNode = uriService.findByUri("/netgrif/test/new_menu_item") - assert leafNode != null - assert item.uriNodeId == uriService.findByUri("/netgrif/test").stringId - assert item.dataSet[MenuItemConstants.FIELD_MENU_ICON].value == "device_hub" - assert item.dataSet[MenuItemConstants.FIELD_MENU_NAME].value == new I18nString("FILTER") - assert item.dataSet[MenuItemConstants.FIELD_IDENTIFIER].value.toString() == "new_menu_item" - assert item.dataSet[MenuItemConstants.FIELD_BANNED_ROLES].options.containsKey("role_2:filter_api_test") - assert item.dataSet[MenuItemConstants.FIELD_ALLOWED_ROLES].options.containsKey("role_1:filter_api_test") - assert item.dataSet[MenuItemConstants.FIELD_USE_TABBED_VIEW].value == true - assert item.dataSet[MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE].value == MenuItemView.TABBED_CASE_VIEW.identifier - - assert filter.dataSet["filter"].filterMetadata["filterType"] == "Case" - assert filter.dataSet["filter"].allowedNets == ["filter", "menu_item"] - assert filter.dataSet["filter"].value == "processIdentifier:filter OR processIdentifier:menu_item" - assert filter.dataSet["filter_type"].value == "Case" - - String tabbedCaseViewId = MenuItemUtils.getCaseIdFromCaseRef(item, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID) - assert tabbedCaseViewId != null - Case tabbedCaseView = workflowService.findOne(tabbedCaseViewId) - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_VIEW_CONTAINS_FILTER].value == true - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_VIEW_FILTER_CASE].value[0] == filter.stringId - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_DEFAULT_HEADERS].value == "meta-title,meta-title" - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_CONFIGURATION_TYPE].value == MenuItemView.TABBED_TASK_VIEW.identifier - - String tabbedTaskViewId = MenuItemUtils.getCaseIdFromCaseRef(tabbedCaseView, TabbedCaseViewConstants.FIELD_VIEW_CONFIGURATION_ID) - assert tabbedTaskViewId != null - Case tabbedTaskView = workflowService.findOne(tabbedTaskViewId) - assert tabbedTaskView.dataSet[TabbedTaskViewConstants.FIELD_VIEW_CONTAINS_FILTER].value == false - assert tabbedTaskView.dataSet[TabbedTaskViewConstants.FIELD_VIEW_FILTER_CASE].value == [] - assert tabbedTaskView.dataSet[TabbedTaskViewConstants.FIELD_DEFAULT_HEADERS].value == "meta-title,meta-title" - - Case testFolder = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue.keyword:\"/netgrif/test\"", PageRequest.of(0, 1))[0] - Case netgrifFolder = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue.keyword:\"/netgrif\"", PageRequest.of(0, 1))[0] - UriNode testNode = uriService.findByUri("/netgrif") - UriNode netgrifNode = uriService.getRoot() - Case rootFolder = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue.keyword:\"/\"", PageRequest.of(0, 1))[0] - - assert testFolder != null && testNode != null - assert testFolder.uriNodeId == testNode.stringId - assert testFolder.dataSet[MenuItemConstants.FIELD_PARENT_ID].value == [netgrifFolder.stringId] - assert (testFolder.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value as ArrayList).contains(item.stringId) - assert item.dataSet[MenuItemConstants.FIELD_PARENT_ID].value == [testFolder.stringId] - assert netgrifFolder.uriNodeId == netgrifNode.stringId - assert netgrifFolder.dataSet[MenuItemConstants.FIELD_PARENT_ID].value == [rootFolder.stringId] - assert (netgrifFolder.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value as ArrayList).contains(testFolder.stringId) - assert rootFolder.dataSet[MenuItemConstants.FIELD_PARENT_ID].value == [] - assert (rootFolder.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value as ArrayList).contains(netgrifFolder.stringId) - } - - @Test - void testChangeFilterAndMenuItems() { - Case caze = createMenuItem() - Thread.sleep(3000) - - Case item = getMenuItem(caze) - String tabbedCaseViewIdBeforeChange = MenuItemUtils.getCaseIdFromCaseRef(item, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID) - Case tabbedCaseViewBeforeChange = workflowService.findOne(tabbedCaseViewIdBeforeChange) - String tabbedTaskViewIdBeforeChange = MenuItemUtils.getCaseIdFromCaseRef(tabbedCaseViewBeforeChange, TabbedCaseViewConstants.FIELD_VIEW_CONFIGURATION_ID) - - def newUri = uriService.getOrCreate("/netgrif/test_new", UriContentType.DEFAULT) - caze = setData(caze, [ - "uri": newUri.uriPath, - "title": "CHANGED FILTER", - "allowed_nets": "filter", - "query": "processIdentifier:filter", - "type": "Case", - "icon": "", - "change_filter_and_menu": "0" - ]) - item = getMenuItem(caze) - Case filter = getFilter(caze) - - assert item.dataSet[MenuItemConstants.FIELD_MENU_NAME].value.toString() == "CHANGED FILTER" - assert item.dataSet[MenuItemConstants.FIELD_ALLOWED_ROLES].options.entrySet()[0].key.contains("role_2") - assert item.dataSet[MenuItemConstants.FIELD_USE_TABBED_VIEW].value == true - assert item.dataSet[MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE].value == MenuItemView.TABBED_CASE_VIEW.identifier - assert item.uriNodeId == newUri.stringId - - assert filter.dataSet["filter"].allowedNets == ["filter"] - assert filter.dataSet["filter"].filterMetadata["defaultSearchCategories"] == false - assert filter.dataSet["filter"].value == "processIdentifier:filter" - - String tabbedCaseViewId = MenuItemUtils.getCaseIdFromCaseRef(item, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID) - assert tabbedCaseViewId != null && tabbedCaseViewId.equals(tabbedCaseViewIdBeforeChange) - Case tabbedCaseView = workflowService.findOne(tabbedCaseViewId) - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_VIEW_CONTAINS_FILTER].value == true - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_VIEW_FILTER_CASE].value[0] == filter.stringId - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_DEFAULT_HEADERS].value == "meta-title,meta-title,meta-title" - assert tabbedCaseView.dataSet[TabbedCaseViewConstants.FIELD_CONFIGURATION_TYPE].value == MenuItemView.TABBED_TASK_VIEW.identifier - - String tabbedTaskViewId = MenuItemUtils.getCaseIdFromCaseRef(tabbedCaseView, TabbedCaseViewConstants.FIELD_VIEW_CONFIGURATION_ID) - assert tabbedTaskViewId != null && tabbedTaskViewId.equals(tabbedTaskViewIdBeforeChange) - Case tabbedTaskView = workflowService.findOne(tabbedTaskViewId) - assert tabbedTaskView.dataSet[TabbedTaskViewConstants.FIELD_VIEW_CONTAINS_FILTER].value == false - assert tabbedTaskView.dataSet[TabbedTaskViewConstants.FIELD_VIEW_FILTER_CASE].value == [] - assert tabbedTaskView.dataSet[TabbedTaskViewConstants.FIELD_DEFAULT_HEADERS].value == "meta-title,meta-title,meta-title" - } - - @Test - void testFindFilter() { - Case caze = createMenuItem() - Case filter = getFilter(caze) - - caze = setData(caze, [ - "find_filter": "0" - ]) - - assert caze.dataSet["found_filter"].value == filter.stringId - } - - @Test - void testMoveMenuItem() { - Case apiCase = createMenuItem("/netgrif/test") - String viewId = apiCase.dataSet["menu_stringId"].value - apiCase = createMenuItem("/netgrif2/test2", "new_menu_item2") - String viewId2 = apiCase.dataSet["menu_stringId"].value - - // move view - Thread.sleep(2000) - apiCase = setData(apiCase, [ - "move_dest_uri": "/netgrif2", - "move_item_id": viewId, - "move_folder_path": null, - "move_item": "0" - ]) - - Case viewCase = workflowService.findOne(viewId) - Thread.sleep(2000) - - UriNode node = uriService.findByUri("/netgrif2") - Case folderCase = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue:\"/netgrif2\"", PageRequest.of(0, 1))[0] - - assert viewCase.uriNodeId == node.stringId - ArrayList childIds = folderCase.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value as ArrayList - assert childIds.contains(viewId) && childIds.size() == 2 - - // cyclic move - assertThrows(IllegalArgumentException.class, () -> { - setData(apiCase, [ - "move_dest_uri": "/netgrif2/cyclic", - "move_item_id": null, - "move_folder_path": "/netgrif2", - "move_item": "0" - ]) - }) - - // move folder - setData(apiCase, [ - "move_dest_uri": "/netgrif/test3", - "move_item_id": null, - "move_folder_path": "/netgrif2", - "move_item": "0" - ]) - Thread.sleep(2000) - - folderCase = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue:\"/netgrif/test3\"", PageRequest.of(0, 1))[0] - Case folderCase2 = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue:\"/netgrif\"", PageRequest.of(0, 1))[0] - assert folderCase != null && folderCase.dataSet[MenuItemConstants.FIELD_PARENT_ID].value == [folderCase2.stringId] - - folderCase = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue:\"/netgrif/test3/netgrif2\"", PageRequest.of(0, 1))[0] - assert folderCase != null - node = uriService.findByUri("/netgrif/test3") - assert node != null - assert folderCase.uriNodeId == node.stringId - assert folderCase.dataSet[MenuItemConstants.FIELD_NODE_PATH].value == "/netgrif/test3/netgrif2" - - childIds = folderCase.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value as ArrayList - assert childIds.size() == 2 - - folderCase = workflowService.findOne(childIds[0]) - node = uriService.findByUri("/netgrif/test3/netgrif2") - assert folderCase.dataSet[MenuItemConstants.FIELD_NODE_PATH].value == "/netgrif/test3/netgrif2/test2" - assert folderCase.uriNodeId == node.stringId - - viewCase = workflowService.findOne(viewId2) - node = uriService.findByUri("/netgrif/test3/netgrif2/test2") - assert viewCase.uriNodeId == node.stringId - } - - @Test - void testDuplicateMenuItem() { - String starterUri = "/netgrif/test" - Case apiCase = createMenuItem(starterUri, "new_menu_item") - Thread.sleep(2000) - - String itemId = apiCase.dataSet["menu_stringId"].value - Case origin = workflowService.findOne(itemId) - Case testFolder = workflowService.findOne((origin.dataSet[MenuItemConstants.FIELD_PARENT_ID].value as ArrayList)[0]) - - String newTitle = "New title" - String newIdentifier = "new_identifier" - - String duplicateTaskId = testFolder.tasks.find { it.transition == "duplicate_item" }.task - taskService.assignTask(duplicateTaskId) - - assertThrows(IllegalArgumentException.class, () -> { - testFolder.dataSet[MenuItemConstants.FIELD_DUPLICATE_TITLE].value = new I18nString("") - testFolder.dataSet[MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER].value = newIdentifier - testFolder = workflowService.save(testFolder) - taskService.finishTask(duplicateTaskId) - }) - - assertThrows(IllegalArgumentException.class, () -> { - testFolder.dataSet[MenuItemConstants.FIELD_DUPLICATE_TITLE].value = new I18nString(newTitle) - testFolder.dataSet[MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER].value = "new_menu_item" - testFolder = workflowService.save(testFolder) - taskService.finishTask(duplicateTaskId) - }) - - testFolder.dataSet[MenuItemConstants.FIELD_DUPLICATE_TITLE].value = new I18nString(newTitle) - testFolder.dataSet[MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER].value = newIdentifier - testFolder = workflowService.save(testFolder) - taskService.finishTask(duplicateTaskId) - - Case duplicated = workflowService.searchOne(QCase.case$.processIdentifier.eq("menu_item") - .and(QCase.case$.dataSet.get(MenuItemConstants.FIELD_IDENTIFIER).value.eq(newIdentifier))) - assert duplicated != null - - UriNode leafNode = uriService.findByUri("/netgrif/" + newIdentifier) - - assert duplicated.uriNodeId == testFolder.uriNodeId - assert leafNode != null - assert duplicated.dataSet[MenuItemConstants.FIELD_DUPLICATE_TITLE].value == new I18nString("") - assert duplicated.dataSet[MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER].value == "" - assert duplicated.title == newTitle - assert duplicated.dataSet[MenuItemConstants.FIELD_MENU_NAME].value == new I18nString(newTitle) - assert duplicated.dataSet[MenuItemConstants.FIELD_IDENTIFIER].value == newIdentifier - assert duplicated.dataSet[MenuItemConstants.FIELD_NODE_PATH].value == "/netgrif/" + newIdentifier - assert duplicated.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value == [] - assert duplicated.dataSet[MenuItemConstants.FIELD_HAS_CHILDREN].value == false - assert duplicated.activePlaces["initialized"] == 1 - } - - List findCasesElastic(String query, Pageable pageable) { - CaseSearchRequest request = new CaseSearchRequest() - request.query = query - List result = elasticCaseService.search([request], userService.system.transformToLoggedUser(), pageable, LocaleContextHolder.locale, false).content - return result - } - - Case createMenuItem(String uri = "/netgrif/test", String identifier = "new_menu_item") { - Case caze = getCase() - caze = setData(caze, [ - "uri": uri, - "title": "FILTER", - "allowed_nets": "filter,menu_item", - "query": "processIdentifier:filter OR processIdentifier:menu_item", - "type": "Case", - "identifier": identifier, - "icon": "device_hub", - "create_filter_and_menu": "0" - ]) - return caze - } - - @Test - void testRemoveMenuItem() { - String starterUri = "/netgrif/test" - Case apiCase = createMenuItem(starterUri, "new_menu_item") - Case leafItemCase = getMenuItem(apiCase) - - sleep(2000) - Case testFolder = findCasesElastic("processIdentifier:$FilterRunner.MENU_NET_IDENTIFIER AND dataSet.${MenuItemConstants.FIELD_NODE_PATH}.textValue:\"/netgrif/test\"", PageRequest.of(0, 1))[0] - String netgrifFolderId = (testFolder.dataSet[MenuItemConstants.FIELD_PARENT_ID].value as ArrayList)[0] - - Case netgrifFolder = workflowService.findOne(netgrifFolderId) - assert (netgrifFolder.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value as ArrayList).contains(testFolder.stringId) - assert workflowService.findOne(testFolder.stringId) != null - assert workflowService.findOne(leafItemCase.stringId) != null - String tabbedCaseViewId = MenuItemUtils.getCaseIdFromCaseRef(leafItemCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID) - assert tabbedCaseViewId != null - Case tabbedCaseView = workflowService.findOne(tabbedCaseViewId) - String tabbedTaskViewId = MenuItemUtils.getCaseIdFromCaseRef(tabbedCaseView, TabbedCaseViewConstants.FIELD_VIEW_CONFIGURATION_ID) - assert tabbedTaskViewId != null - - workflowService.deleteCase(testFolder) - sleep(2000) - netgrifFolder = workflowService.findOne(netgrifFolderId) - assert !(netgrifFolder.dataSet[MenuItemConstants.FIELD_CHILD_ITEM_IDS].value as ArrayList).contains(testFolder.stringId) - assertThrows(IllegalArgumentException.class, () -> { - workflowService.findOne(testFolder.stringId) - }) - assertThrows(IllegalArgumentException.class, () -> { - workflowService.findOne(leafItemCase.stringId) - }) - assertThrows(IllegalArgumentException.class, () -> { - workflowService.findOne(tabbedCaseViewId) - }) - assertThrows(IllegalArgumentException.class, () -> { - workflowService.findOne(tabbedTaskViewId) - }) - } - - Case getCase() { - return workflowService.searchOne(QCase.case$.processIdentifier.eq("filter_api_test")) - } - - Case getMenuItem(Case caze) { - return workflowService.findOne(caze.dataSet["menu_stringId"].value as String) - } - - Case getFilter(Case caze) { - return workflowService.findOne(caze.dataSet["filter_stringId"].value as String) - } - - def setData(Case caze, Map dataSet) { - dataService.setData(caze.tasks[0].task, ImportHelper.populateDataset(dataSet.collectEntries { - [(it.key): (["value": it.value, "type": "text"])] - })) - return workflowService.findOne(caze.stringId) - } - -} diff --git a/src/test/groovy/com/netgrif/application/engine/export/service/XlsExportServiceTest.java b/src/test/groovy/com/netgrif/application/engine/export/service/XlsExportServiceTest.java index 4abac8a4822..27955dc119d 100644 --- a/src/test/groovy/com/netgrif/application/engine/export/service/XlsExportServiceTest.java +++ b/src/test/groovy/com/netgrif/application/engine/export/service/XlsExportServiceTest.java @@ -1,11 +1,9 @@ package com.netgrif.application.engine.export.service; -import com.netgrif.application.engine.auth.domain.IUser; import com.netgrif.application.engine.auth.domain.LoggedUser; -import com.netgrif.application.engine.auth.service.interfaces.IUserService; import com.netgrif.application.engine.elastic.web.requestbodies.CaseSearchRequest; import com.netgrif.application.engine.export.service.interfaces.IXlsExportService; -import com.netgrif.application.engine.startup.FilterRunner; +import com.netgrif.application.engine.menu.domain.MenuItemConstants; import com.netgrif.application.engine.startup.SuperCreator; import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService; import com.netgrif.application.engine.export.web.requestbodies.FilteredCasesRequest; @@ -42,7 +40,7 @@ public class XlsExportServiceTest { void shouldCreateXlsxFile() throws Exception { LoggedUser superUser = superCreator.getSuperUser().transformToLoggedUser(); - IntStream.range(0,5).forEach(idx -> workflowService.createCaseByIdentifier(FilterRunner.MENU_NET_IDENTIFIER, "Test case", "", superUser)); + IntStream.range(0,5).forEach(idx -> workflowService.createCaseByIdentifier(MenuItemConstants.PROCESS_IDENTIFIER, "Test case", "", superUser)); FilteredCasesRequest request = getTestRequest(); File excel = xlsExportService.getExportFilteredCasesFile(request, superUser, Locale.ENGLISH); @@ -59,7 +57,7 @@ FilteredCasesRequest getTestRequest() { FilteredCasesRequest request = new FilteredCasesRequest(); request.setQuery(List.of( CaseSearchRequest.builder() - .query("processIdentifier:" + FilterRunner.MENU_NET_IDENTIFIER) + .query("processIdentifier:" + MenuItemConstants.PROCESS_IDENTIFIER) .build())); request.setSelectedDataFieldNames(List.of("Menu Item Identifier", "Item URI", "Menu icon identifier", "Name of the item", "Tab icon identifier", "Name of the item")); request.setSelectedDataFieldIds(List.of("menu_item_identifier", "nodePath", "menu_icon", "menu_name", "tab_icon", "tab_name")); diff --git a/src/test/groovy/com/netgrif/application/engine/filters/FilterImportExportTest.groovy b/src/test/groovy/com/netgrif/application/engine/filters/FilterImportExportTest.groovy deleted file mode 100644 index d726724f21b..00000000000 --- a/src/test/groovy/com/netgrif/application/engine/filters/FilterImportExportTest.groovy +++ /dev/null @@ -1,546 +0,0 @@ -package com.netgrif.application.engine.filters - -import com.netgrif.application.engine.TestHelper -import com.netgrif.application.engine.auth.domain.Authority -import com.netgrif.application.engine.auth.domain.User -import com.netgrif.application.engine.auth.domain.UserState -import com.netgrif.application.engine.petrinet.domain.PetriNet -import com.netgrif.application.engine.petrinet.domain.dataset.FileFieldValue -import com.netgrif.application.engine.petrinet.domain.roles.ProcessRole -import com.netgrif.application.engine.startup.DefaultFiltersRunner -import com.netgrif.application.engine.startup.FilterRunner -import com.netgrif.application.engine.startup.ImportHelper -import com.netgrif.application.engine.workflow.domain.* -import com.netgrif.application.engine.workflow.domain.filter.FilterImportExportList -import com.netgrif.application.engine.workflow.service.UserFilterSearchService -import com.netgrif.application.engine.workflow.service.interfaces.IDataService -import com.netgrif.application.engine.workflow.service.interfaces.IFilterImportExportService -import com.netgrif.application.engine.workflow.service.interfaces.ITaskService -import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Disabled -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.core.io.ClassPathResource -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken -import org.springframework.security.core.Authentication -import org.springframework.security.core.context.SecurityContextHolder -import org.springframework.test.context.ActiveProfiles -import org.springframework.test.context.junit.jupiter.SpringExtension - -import javax.xml.XMLConstants -import javax.xml.transform.stream.StreamSource -import javax.xml.validation.Schema -import javax.xml.validation.SchemaFactory -import javax.xml.validation.Validator -import java.util.stream.Collectors - -@ExtendWith(SpringExtension.class) -@ActiveProfiles(["test"]) -@SpringBootTest -class FilterImportExportTest { - - public static final String DUMMY_USER_MAIL = "dummy@netgrif.com" - public static final String DUMMY_USER_PASSWORD = "password" - - private static final String EXPORT_NET_IDENTIFIER = "export_filters" - private static final String IMPORT_NET_IDENTIFIER = "import_filters" - - private static final int DEFAULT_FILTERS_SIZE = 5 - private static final String[] FILTERS_TO_EXPORT = ["My cases", "My tasks", "Test filter"] - private static final String[] FILTERS_TO_EXPORT_NEW = ["My cases new", "My tasks new", "Test filter new"] - - private static final String FILTER_VISIBILITY_PUBLIC = "public" - private static final String FILTER_VISIBILITY_PRIVATE = "private" - - private static final String GERMAN_ISO_3166_CODE = "de" - private static final String SLOVAK_ISO_3166_CODE = "sk" - - private static final String UPLOAD_FILE_FIELD = "upload_file" - private static final String NEW_TITLE_FIELD = "new_title" - private static final String VISIBILITY_FIELD = "visibility" - private static final String IMPORTED_FILTERS_FIELD = "imported_filters" - private static final String FILTER_FIELD = "filter" - - @Autowired - IFilterImportExportService importExportService - - @Autowired - FilterRunner filterRunner - - @Autowired - TestHelper testHelper - - @Autowired - IWorkflowService workflowService - - @Autowired - ImportHelper importHelper - - @Autowired - DefaultFiltersRunner defaultFiltersRunner - - @Autowired - UserFilterSearchService userFilterSearchService - - @Autowired - ITaskService taskService - - @Autowired - private IDataService dataService - - private Authentication userAuth - private User dummyUser - private Case importCase - private Case exportCase - - @BeforeEach - void setup() { - this.testHelper.truncateDbs() - this.defaultFiltersRunner.run() - createTestFilter() - dummyUser = createDummyUser() - userAuth = new UsernamePasswordAuthenticationToken(dummyUser.transformToLoggedUser(), DUMMY_USER_PASSWORD) - SecurityContextHolder.getContext().setAuthentication(userAuth) - - Optional importNet = this.filterRunner.createImportFiltersNet() - Optional exportNet = this.filterRunner.createExportFiltersNet() - assert importNet.isPresent() - assert exportNet.isPresent() - - importCase = this.workflowService.searchOne( - QCase.case$.processIdentifier.eq(IMPORT_NET_IDENTIFIER).and(QCase.case$.author.email.eq(DUMMY_USER_MAIL)) - ) - exportCase = this.workflowService.searchOne( - QCase.case$.processIdentifier.eq(EXPORT_NET_IDENTIFIER).and(QCase.case$.author.email.eq(DUMMY_USER_MAIL)) - ) - assert importCase != null - assert exportCase != null - } - - @Test - @Disabled("Fixne DJ") - void createImportExportFiltersNet() { - List filterCases = this.userFilterSearchService.autocompleteFindFilters("") - assert filterCases.size() == DEFAULT_FILTERS_SIZE - - Set exportFiltersIds = filterCases.stream() - .filter({ filterCase -> filterCase.title in FILTERS_TO_EXPORT }) - .map({ filterCase -> filterCase.stringId }) - .collect(Collectors.toSet()) - FileFieldValue exportedFiltersField = this.importExportService.exportFiltersToFile(exportFiltersIds) - File exportedFiltersFile = new File(exportedFiltersField.getPath()) - assert exportedFiltersFile.exists() - - importCase.dataSet.get(UPLOAD_FILE_FIELD).value = exportedFiltersField - this.workflowService.save(importCase) - List importedTasksIds = this.importExportService.importFilters() - assert importedTasksIds.size() == FILTERS_TO_EXPORT.size() - - validateFilterXML(new FileInputStream(exportedFiltersField.getPath())) - importedTasksIds.forEach({ taskId -> - Task filterTask = this.taskService.findOne(taskId) - this.dataService.setData(filterTask, ImportHelper.populateDataset([ - (VISIBILITY_FIELD): [ - "type" : "enumeration_map", - "value": FILTER_VISIBILITY_PRIVATE - ], - (NEW_TITLE_FIELD) : [ - "type" : "text", - "value": this.workflowService.findOne(filterTask.caseId).title + " new" - ] - ])) - }) - Task importTask = this.taskService.searchOne(QTask.task.caseId.eq(importCase.stringId).and(QTask.task.transitionId.eq("importFilter"))) - this.dataService.setData(importTask, ImportHelper.populateDataset([ - (IMPORTED_FILTERS_FIELD): [ - "type" : "taskRef", - "value": importedTasksIds - ] - ])) - this.taskService.finishTask(importTask, dummyUser) - Thread.sleep(1000) - filterCases = this.userFilterSearchService.autocompleteFindFilters("") - List filterCasesNames = filterCases.stream().map({ filterCase -> filterCase.title }).collect(Collectors.toList()) - assert filterCases.size() == DEFAULT_FILTERS_SIZE + FILTERS_TO_EXPORT.size() - - for (String filterName : FILTERS_TO_EXPORT_NEW) { - assert filterName in filterCasesNames - } - for (Case filterCase : filterCases) { - if (filterCase.title in FILTERS_TO_EXPORT_NEW) { - assert filterCase.dataSet.get(VISIBILITY_FIELD).value == FILTER_VISIBILITY_PRIVATE - } - } - for (int i = 0; i < FILTERS_TO_EXPORT.size(); i++) { - Case filterCase1 = filterCases.get(filterCasesNames.indexOf(FILTERS_TO_EXPORT[i])) - DataField filterField1 = filterCase1.dataSet.get(FILTER_FIELD) - Case filterCase2 = filterCases.get(filterCasesNames.indexOf(FILTERS_TO_EXPORT_NEW[i])) - DataField filterField2 = filterCase2.dataSet.get(FILTER_FIELD) - assert filterCase1.icon == filterCase2.icon - assert filterField1.value == filterField2.value - assert filterField1.allowedNets == filterField2.allowedNets - assert filterField1.filterMetadata == filterField2.filterMetadata - } - } - - @Test - void importExportChainedFilters() { - Optional filter1Opt = defaultFiltersRunner.createCaseFilter( - "Link 1", - "home", - FILTER_VISIBILITY_PUBLIC, - "(author:<>)", - [], - ["predicateMetadata" : [ - [[ - "category" : "case_author", - "configuration": [ - "operator": "equals" - ], - "values" : [[ - "text" : "search.category.userMe", - "value": ["<>"] - ]] - ]] - ], "searchCategories": ["case_author"]], - [:] - ) - assert filter1Opt.isPresent() - Case filter1 = filter1Opt.get() - Optional filter2Opt = defaultFiltersRunner.createCaseFilter( - "Link 2", - "home", - FILTER_VISIBILITY_PUBLIC, - "(author:<>)", - [], - ["predicateMetadata" : [ - [[ - "category" : "case_author", - "configuration": [ - "operator": "equals" - ], - "values" : [[ - "text" : "search.category.userMe", - "value": ["<>"] - ]] - ]] - ], "searchCategories": ["case_author"]], - [:], - true, - true, - filter1.getStringId() - ) - assert filter2Opt.isPresent() - Case filter2 = filter2Opt.get() - Optional filter3Opt = defaultFiltersRunner.createCaseFilter( - "Link 3", - "home", - FILTER_VISIBILITY_PUBLIC, - "(author:<>)", - [], - ["predicateMetadata" : [ - [[ - "category" : "case_author", - "configuration": [ - "operator": "equals" - ], - "values" : [[ - "text" : "search.category.userMe", - "value": ["<>"] - ]] - ]] - ], "searchCategories": ["case_author"]], - [:], - true, - true, - filter1.getStringId() - ) - assert filter3Opt.isPresent() - Case filter3 = filter3Opt.get() - - FilterImportExportList exported = importExportService.exportFilters([filter2.getStringId(), filter3.getStringId()]) - assert exported != null - assert exported.filters != null - assert exported.filters.size() == 3 - assert exported.filters.get(0).caseId == filter1.getStringId() - assert exported.filters.get(0).parentCaseId == null - assert exported.filters.get(0).parentViewId == null - assert exported.filters.get(1).caseId == filter2.getStringId() - assert exported.filters.get(1).parentCaseId == filter1.getStringId() - assert exported.filters.get(1).parentViewId == null - assert exported.filters.get(2).caseId == filter3.getStringId() - assert exported.filters.get(2).parentCaseId == filter1.getStringId() - assert exported.filters.get(2).parentViewId == null - - Map imported = importExportService.importFilters(exported) - assert imported != null - assert imported.size() == 3 - - List importedTasks = taskService.findAllById(new ArrayList(imported.values())) - assert importedTasks.size() == 3 - - Map invertedMap = imported.collectEntries { k, v -> [v, k] } - Map newToOldCaseId = importedTasks.collectEntries { t -> [t.caseId, invertedMap.get(t.getStringId())] } - Map idToOldCase = [filter1, filter2, filter3].collectEntries { c -> [c.stringId, c] } - - - List importedCases = workflowService.findAllById(new ArrayList(newToOldCaseId.keySet())) - assert importedCases.size() == 3 - - importedCases.forEach({ c -> - Case oldCase = idToOldCase.get(newToOldCaseId.get(c.getStringId())) - assert oldCase != null - assert newToOldCaseId.get(c.dataSet.get("origin_view_id").value) == oldCase.dataSet.get("origin_view_id").value - assert newToOldCaseId.get(c.dataSet.get("parent_filter_id").value) == oldCase.dataSet.get("parent_filter_id").value - }) - } - - private User createDummyUser() { - def auths = importHelper.createAuthorities(["user": Authority.user, "admin": Authority.admin]) - return importHelper.createUser(new User(name: "Dummy", surname: "User", email: DUMMY_USER_MAIL, password: DUMMY_USER_PASSWORD, state: UserState.ACTIVE), - [auths.get("user")] as Authority[], - [] as ProcessRole[]) - } - - private static void validateFilterXML(InputStream xml) throws IllegalFilterFileException { - try { - SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI) - Schema schema = factory.newSchema(new ClassPathResource("/petriNets/filter_export_schema.xsd").URL) - Validator validator = schema.newValidator() - validator.validate(new StreamSource(xml)) - } catch (Exception ex) { - throw new IllegalFilterFileException(ex) - } - } - - void createTestFilter() { - defaultFiltersRunner.createCaseFilter("Test filter", "filter_alt", FILTER_VISIBILITY_PUBLIC, - "((((dataSet.number.numberValue:5) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.number.numberValue:[10 TO 100.548]) AND " + - "(processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.text.fulltextValue:*asdad*) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) " + - "OR ((dataSet.enumeration.fulltextValue:*asdasd*) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.enumeration_map.fulltextValue:*asdasd*) " + - "AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.multichoice.fulltextValue:*asdasd*) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) " + - "OR ((dataSet.boolean.booleanValue:true) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.boolean.booleanValue:false) AND " + - "(processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.date.timestampValue:[1631138400000 TO 1631224800000}) AND " + - "(processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.date.timestampValue:[1631138400000 TO 1631311200000}) AND " + - "(processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.file.fileNameValue:*asdasd*) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) OR " + - "((dataSet.fileList.fileNameValue:*asdasd*) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.user.userIdValue:<>) AND " + - "(processIdentifier:6139e51308215f25b0a498c2_all_data)) OR ((dataSet.user.userIdValue:7) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) " + - "OR ((dataSet.datetime.timestampValue:[1631184300000 TO 1631184360000}) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) OR " + - "((dataSet.datetime.timestampValue:[1631184360000 TO 1631270820000}) AND (processIdentifier:6139e51308215f25b0a498c2_all_data))) AND (title:*asdasd*) AND " + - "((creationDateSortable:[1631138400000 TO 1631224800000}) OR (creationDateSortable:[1631138400000 TO 1631311200000})) AND " + - "((creationDateSortable:[1631184360000 TO 1631184420000}) OR (creationDateSortable:[1631184360000 TO 1631270820000})) AND " + - "(processIdentifier:6139e51308215f25b0a498c2_all_data) AND ((taskIds:1) AND (processIdentifier:6139e51308215f25b0a498c2_all_data)) AND " + - "((author:<>) OR (!(author:7))) AND (visualId:*asdad*) AND (stringId:*asdasd*))", ["all_data", "test_net"], - ["predicateMetadata": [ - [[ - "category" : "case_dataset", - "configuration": [ - "operator" : "equals", - "datafield": "number#Number" - ], - "values" : [5] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "in_range", - "datafield": "number#Number" - ], - "values" : [10, 100.548] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "substring", - "datafield": "text#Text" - ], - "values" : ["asdad"] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "substring", - "datafield": "enumeration#Enumeration" - ], - "values" : ["asdasd"] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "substring", - "datafield": "enumeration_map#Enumeration Map" - ], - "values" : ["asdasd"] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "substring", - "datafield": "multichoice#Multichoice" - ], - "values" : ["asdasd"] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "equals", - "datafield": "boolean#Boolean" - ], - "values" : [true] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "equals", - "datafield": "boolean#Boolean" - ], - "values" : [false] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "equals_date", - "datafield": "date#Date" - ], - "values" : [1631138400000] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "in_range_date", - "datafield": "date#Date" - ], - "values" : [1631138400000, 1631224800000] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "substring", - "datafield": "file#File" - ], - "values" : ["asdasd"] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "substring", - "datafield": "fileList#File List" - ], - "values" : ["asdasd"] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "equals", - "datafield": "user#User" - ], - "values" : [[ - "text" : "search.category.userMe", - "value": ["<>"] - ]] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "equals", - "datafield": "user#User" - ], - "values" : [[ - "text" : "Admin Netgrif", - "value": [7] - ]] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "equals_date_time", - "datafield": "dateTime#Datetime" - ], - "values" : [1631184356623] - ], [ - "category" : "case_dataset", - "configuration": [ - "operator" : "in_range_date_time", - "datafield": "dateTime#Datetime" - ], - "values" : [1631184364266, 1631270767000] - ]], - [[ - "category" : "case_title", - "configuration": [ - "operator": "substring" - ], - "values" : ["asdasd"] - ]], - [[ - "category" : "case_creation_date", - "configuration": [ - "operator": "equals_date" - ], - "values" : [1631138400000] - ], [ - "category" : "case_creation_date", - "configuration": [ - "operator": "in_range_date" - ], - "values" : [1631138400000, 1631224800000] - ]], - [[ - "category" : "case_creation_date_time", - "configuration": [ - "operator": "equals_date_time" - ], - "values" : [1631184402526] - ], [ - "category" : "case_creation_date_time", - "configuration": [ - "operator": "in_range_date_time" - ], - "values" : [1631184408995, 1631270810000] - ]], - [[ - "category" : "case_process", - "configuration": [ - "operator": "equals" - ], - "values" : ["All Data"] - ]], - [[ - "category" : "case_task", - "configuration": [ - "operator": "equals" - ], - "values" : ["Task - editable"] - ]], - [[ - "category" : "case_author", - "configuration": [ - "operator": "equals" - ], - "values" : [[ - "text" : "search.category.userMe", - "value": ["<>"] - ]] - ], [ - "category" : "case_author", - "configuration": [ - "operator": "not_equals" - ], - "values" : [[ - "text" : "Admin Netgrif", - "value": [7] - ]] - ]], - [[ - "category" : "case_visual_id", - "configuration": [ - "operator": "substring" - ], - "values" : ["asdad"] - ]], - [[ - "category" : "case_string_id", - "configuration": [ - "operator": "substring" - ], - "values" : ["asdasd"] - ]] - ], - "searchCategories" : ["case_dataset", "case_title", "case_creation_date", "case_creation_date_time", "case_process", "case_task", "case_author", "case_visual_id", "case_string_id"]], - [ - (GERMAN_ISO_3166_CODE): "Testfilter", - (SLOVAK_ISO_3166_CODE): "Testovaci filter" - ] - ) - } - -} diff --git a/src/test/groovy/com/netgrif/application/engine/filters/FilterTest.groovy b/src/test/groovy/com/netgrif/application/engine/filters/FilterTest.groovy new file mode 100644 index 00000000000..b05c90887cf --- /dev/null +++ b/src/test/groovy/com/netgrif/application/engine/filters/FilterTest.groovy @@ -0,0 +1,87 @@ +package com.netgrif.application.engine.filters + +import com.netgrif.application.engine.TestHelper +import com.netgrif.application.engine.auth.service.UserService +import com.netgrif.application.engine.petrinet.domain.PetriNet +import com.netgrif.application.engine.petrinet.domain.VersionType +import com.netgrif.application.engine.petrinet.domain.dataset.CaseFilterField +import com.netgrif.application.engine.petrinet.domain.dataset.ProcessFilterField +import com.netgrif.application.engine.petrinet.domain.dataset.TaskFilterField +import com.netgrif.application.engine.petrinet.service.PetriNetService +import com.netgrif.application.engine.startup.ImportHelper +import com.netgrif.application.engine.startup.SuperCreator +import com.netgrif.application.engine.workflow.domain.Case +import com.netgrif.application.engine.workflow.service.interfaces.IDataService +import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ActiveProfiles +import org.springframework.test.context.junit.jupiter.SpringExtension + +import static org.testng.AssertJUnit.assertEquals + +@SpringBootTest +@ActiveProfiles(["test"]) +@ExtendWith(SpringExtension.class) +class FilterTest { + + private static final String PROCESS_PATH = "src/test/resources/petriNets/filter_test.xml" + + @Autowired + private TestHelper testHelper + + @Autowired + private IWorkflowService workflowService + + @Autowired + private ImportHelper importHelper + + @Autowired + private UserService userService + + @Autowired + private IDataService dataService + + @Autowired + private PetriNetService petriNetService + + @Autowired + private SuperCreator superCreator + + @BeforeEach + void beforeEach() { + testHelper.truncateDbs() + } + + @Test + void filterTest() { + InputStream inputStream = new FileInputStream(PROCESS_PATH) + PetriNet testProcess = petriNetService.importPetriNet(inputStream, VersionType.MAJOR, superCreator.loggedSuper).getNet() + inputStream.close() + assertEquals(CaseFilterField.class, testProcess.getField("filter_field").get().class) + assertEquals(CaseFilterField.class, testProcess.getField("case_filter_field").get().class) + assertEquals(TaskFilterField.class, testProcess.getField("task_filter_field").get().class) + assertEquals(ProcessFilterField.class, testProcess.getField("process_filter_field").get().class) + + Case testCase = workflowService.createCase(testProcess.stringId, "", "", superCreator.loggedSuper).case + assertEquals("someQueryString", testCase.getFieldValue("filter_field")) + assertEquals("someQueryString", testCase.getFieldValue("case_filter_field")) + assertEquals("someQueryString", testCase.getFieldValue("task_filter_field")) + assertEquals("someQueryString", testCase.getFieldValue("process_filter_field")) + + String taskId = testCase.tasks.find { taskPair -> taskPair.transition == "t1" }.task + testCase = dataService.setData(taskId, ImportHelper.populateDataset([ + "filter_field": ["type": "filter", "value": "newQueryString"], + "case_filter_field": ["type": "caseFilter", "value": "newQueryString"], + "task_filter_field": ["type": "taskFilter", "value": "newQueryString"], + "process_filter_field": ["type": "processFilter", "value": "newQueryString"], + ])).case + assertEquals("newQueryString", testCase.getFieldValue("filter_field")) + assertEquals("newQueryString", testCase.getFieldValue("case_filter_field")) + assertEquals("newQueryString", testCase.getFieldValue("task_filter_field")) + assertEquals("newQueryString", testCase.getFieldValue("process_filter_field")) + } +} diff --git a/src/test/groovy/com/netgrif/application/engine/menu/MenuImportExportTest.groovy b/src/test/groovy/com/netgrif/application/engine/menu/MenuImportExportTest.groovy index 940fa30b79e..98d06dc2b94 100644 --- a/src/test/groovy/com/netgrif/application/engine/menu/MenuImportExportTest.groovy +++ b/src/test/groovy/com/netgrif/application/engine/menu/MenuImportExportTest.groovy @@ -17,9 +17,7 @@ import com.netgrif.application.engine.workflow.domain.Task import com.netgrif.application.engine.workflow.domain.eventoutcomes.dataoutcomes.SetDataEventOutcome import com.netgrif.application.engine.menu.domain.MenuAndFilters import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository -import com.netgrif.application.engine.workflow.service.UserFilterSearchService import com.netgrif.application.engine.workflow.service.interfaces.IDataService -import com.netgrif.application.engine.workflow.service.interfaces.IMenuImportExportService import com.netgrif.application.engine.workflow.service.interfaces.ITaskService import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService import org.junit.jupiter.api.BeforeEach @@ -72,10 +70,7 @@ class MenuImportExportTest { "Menu entry \"My tasks\": OK\n" @Autowired - IMenuImportExportService menuImportExportService - - @Autowired - FilterRunner filterRunner + MenuRunner menuRunner @Autowired TestHelper testHelper @@ -89,12 +84,6 @@ class MenuImportExportTest { @Autowired ImportHelper importHelper - @Autowired - DefaultFiltersRunner defaultFiltersRunner - - @Autowired - UserFilterSearchService userFilterSearchService - @Autowired ITaskService taskService @@ -123,7 +112,6 @@ class MenuImportExportTest { @BeforeEach void beforeTest() { this.testHelper.truncateDbs(); - this.defaultFiltersRunner.run() this.dummyUser = createDummyUser(); } diff --git a/src/test/java/com/netgrif/application/engine/menu/MenuItemServiceTest.java b/src/test/java/com/netgrif/application/engine/menu/MenuItemServiceTest.java new file mode 100644 index 00000000000..1ab30a687e7 --- /dev/null +++ b/src/test/java/com/netgrif/application/engine/menu/MenuItemServiceTest.java @@ -0,0 +1,779 @@ +package com.netgrif.application.engine.menu; + +import com.mongodb.client.MongoCollection; +import com.netgrif.application.engine.TestHelper; +import com.netgrif.application.engine.auth.service.interfaces.IUserService; +import com.netgrif.application.engine.elastic.service.interfaces.IElasticCaseService; +import com.netgrif.application.engine.menu.domain.*; +import com.netgrif.application.engine.menu.domain.configurations.*; +import com.netgrif.application.engine.menu.domain.templates.CustomViewTemplate; +import com.netgrif.application.engine.menu.domain.templates.SimpleTaskViewTemplate; +import com.netgrif.application.engine.menu.domain.templates.TabbedCaseViewTemplate; +import com.netgrif.application.engine.menu.domain.templates.Template; +import com.netgrif.application.engine.menu.service.MenuItemService; +import com.netgrif.application.engine.menu.service.MenuItemTemplateHolder; +import com.netgrif.application.engine.menu.utils.MenuItemUtils; +import com.netgrif.application.engine.petrinet.domain.DataGroup; +import com.netgrif.application.engine.petrinet.domain.I18nString; +import com.netgrif.application.engine.petrinet.domain.UriNode; +import com.netgrif.application.engine.petrinet.domain.dataset.FieldType; +import com.netgrif.application.engine.petrinet.domain.throwable.TransitionNotExecutableException; +import com.netgrif.application.engine.petrinet.service.interfaces.IUriService; +import com.netgrif.application.engine.startup.ImportHelper; +import com.netgrif.application.engine.startup.SuperCreator; +import com.netgrif.application.engine.workflow.domain.Case; +import com.netgrif.application.engine.workflow.domain.DataField; +import com.netgrif.application.engine.workflow.domain.TaskPair; +import com.netgrif.application.engine.workflow.domain.repositories.CaseRepository; +import com.netgrif.application.engine.workflow.service.interfaces.IDataService; +import com.netgrif.application.engine.workflow.service.interfaces.ITaskService; +import com.netgrif.application.engine.workflow.service.interfaces.IWorkflowService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest +@ActiveProfiles({"test"}) +@ExtendWith(SpringExtension.class) +public class MenuItemServiceTest { + + @Autowired + private TestHelper testHelper; + + @Autowired + private MenuItemService menuItemService; + + @Autowired + private SuperCreator superCreator; + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private CaseRepository caseRepository; + + @Autowired + private IUriService uriService; + + @Autowired + private IWorkflowService workflowService; + + @Autowired + private IUserService userService; + + @Autowired + private IDataService dataService; + + @Autowired + private ITaskService taskService; + + @BeforeEach + public void beforeEach() { + testHelper.truncateDbs(); + } + + @Test + public void ensureDatabaseIndexesTest() { + mongoTemplate.getDb().drop(); + + MongoCollection collection = mongoTemplate.getDb().getCollection("case", Case.class); + long indexCountBefore = collection.listIndexes().into(new java.util.ArrayList<>()).size(); + assertEquals(0, indexCountBefore, "Expected no indexes after dropping database"); + + menuItemService.ensureDatabaseIndexes(); + + long indexCountAfter = collection.listIndexes().into(new java.util.ArrayList<>()).size(); + assertTrue(indexCountAfter > indexCountBefore, "Expected indexes to be created after calling ensureDatabaseIndexes"); + } + + @Test + public void createMenuItemTest() throws TransitionNotExecutableException { + assertThrows(IllegalArgumentException.class, () -> menuItemService.createMenuItem(null)); + MenuItemBody emptyBody = new MenuItemBody(); + assertThrows(IllegalArgumentException.class, () -> menuItemService.createMenuItem(emptyBody)); + emptyBody.setUri("/"); + assertThrows(IllegalArgumentException.class, () -> menuItemService.createMenuItem(emptyBody)); + emptyBody.setIdentifier("xxx"); + assertDoesNotThrow(() -> menuItemService.createMenuItem(emptyBody)); + emptyBody.setUri("/xxx2"); + emptyBody.setIdentifier("xxx3"); + assertDoesNotThrow(() -> menuItemService.createMenuItem(emptyBody)); + emptyBody.setUri("/xxx4"); + emptyBody.setIdentifier("xxx4"); + assertThrows(IllegalArgumentException.class, () -> menuItemService.createMenuItem(emptyBody)); + + Map templateOptions = MenuItemTemplateHolder.transformToOptions(); + templateOptions.keySet().forEach((templateIdentifier) -> { + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(templateIdentifier, + uriService.getRoot().getUriPath(), templateIdentifier); + assertTrue(menuItemBodyOpt.isPresent()); + try { + createByTemplateAndAssert(menuItemBodyOpt.get()); + } catch (TransitionNotExecutableException e) { + throw new RuntimeException(e); + } + }); + + createAndAssertDetailed(); + } + + @SuppressWarnings("unchecked") + private void createByTemplateAndAssert(MenuItemBody menuItemBody) throws TransitionNotExecutableException { + caseRepository.deleteAll(); + Case menuItemCase = menuItemService.createMenuItem(menuItemBody); + + UriNode uriNode = uriService.findByUri(menuItemBody.getUri()); + assertEquals(uriNode.getStringId(), menuItemCase.getUriNodeId()); + + assertEquals(menuItemBody.getIdentifier(), menuItemCase.getFieldValue(MenuItemConstants.FIELD_IDENTIFIER)); + I18nString actualMenuName = (I18nString) menuItemCase.getFieldValue(MenuItemConstants.FIELD_MENU_NAME); + assertTrue(actualMenuName.equals(menuItemBody.getMenuName()) || actualMenuName.equals(new I18nString(menuItemBody.getIdentifier()))); + assertEquals(menuItemBody.isUseTabbedView(), menuItemCase.getFieldValue(MenuItemConstants.FIELD_USE_TABBED_VIEW)); + assertEquals(menuItemBody.isUseCustomView(), menuItemCase.getFieldValue(MenuItemConstants.FIELD_USE_CUSTOM_VIEW)); + assertEquals(menuItemBody.getConfigurationTemplateIdentifier(), menuItemCase.getFieldValue(MenuItemConstants.FIELD_CONFIGURATION_TEMPLATES)); + assertEquals((menuItemBody.getUri() + uriService.getUriSeparator() + menuItemBody.getIdentifier()).replaceAll("//", uriService.getUriSeparator()), + menuItemCase.getFieldValue(MenuItemConstants.FIELD_NODE_PATH)); + + if (menuItemBody.getView() == null) { + assertEquals(1 + 1, caseRepository.count()); + + List viewConfigurationIdValue = (List) menuItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertTrue(viewConfigurationIdValue == null || viewConfigurationIdValue.isEmpty()); + + List viewConfigurationFormValue = (List) menuItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_FORM); + assertTrue(viewConfigurationFormValue == null || viewConfigurationFormValue.isEmpty()); + + List viewConfigurationAllDataFormValue = (List) menuItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM); + assertTrue(viewConfigurationAllDataFormValue == null || viewConfigurationAllDataFormValue.isEmpty()); + } else { + List viewConfigurationIdValue = (List) menuItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertEquals(1, viewConfigurationIdValue.size()); + Case viewCase = workflowService.findOne(viewConfigurationIdValue.get(0)); + + List viewConfigurationFormValue = (List) menuItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_FORM); + assertEquals(1, viewConfigurationFormValue.size()); + assertTrue(viewConfigurationFormValue.contains(getTaskId(viewCase, ViewConstants.TRANS_SETTINGS_ID))); + + List viewConfigurationAllDataFormValue = (List) menuItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM); + assertEquals(1, viewConfigurationAllDataFormValue.size()); + assertTrue(viewConfigurationAllDataFormValue.contains(getTaskId(viewCase, ViewConstants.TRANS_ALL_MENU_DATA_ID))); + + if (!menuItemBody.getView().hasAssociatedView()) { + assertEquals(2 + 1, caseRepository.count()); + } else { + assertEquals(3 + 1, caseRepository.count()); + + List nextViewConfigurationIdValue = (List) viewCase.getFieldValue(ViewConstants.FIELD_VIEW_CONFIGURATION_ID); + assertEquals(1, nextViewConfigurationIdValue.size()); + Case nextViewCase = workflowService.findOne(nextViewConfigurationIdValue.get(0)); + + List nextViewConfigurationFormValue = (List) viewCase.getFieldValue(ViewConstants.FIELD_VIEW_CONFIGURATION_FORM); + assertEquals(1, nextViewConfigurationFormValue.size()); + assertTrue(nextViewConfigurationFormValue.contains(getTaskId(nextViewCase, ViewConstants.TRANS_SETTINGS_ID))); + + List nextViewConfigurationAllDataFormValue = (List) viewCase.getFieldValue(ViewConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM); + assertEquals(1, nextViewConfigurationAllDataFormValue.size()); + assertTrue(nextViewConfigurationAllDataFormValue.contains(getTaskId(nextViewCase, ViewConstants.TRANS_ALL_MENU_DATA_ID))); + } + } + } + + @SuppressWarnings("unchecked") + private void createAndAssertDetailed() throws TransitionNotExecutableException { + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(TabbedCaseViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri("/netgrif/test"); + menuItemBody.setIdentifier("new_menu_item"); + menuItemBody.setMenuIcon("device_hub"); + assertNotNull(menuItemBody.getView()); + assertNotNull(menuItemBody.getView().getFilterBody()); + menuItemBody.getView().getFilterBody().setQuery("processIdentifier:menu_item"); + menuItemBody.getView().getFilterBody().setType(FieldType.CASE_FILTER); + ((CaseViewBody) menuItemBody.getView()).setDefaultHeaders(List.of("meta-title", "meta-processIdentifier")); + assertNotNull(menuItemBody.getView().getAssociatedViewBody()); + ((TaskViewBody) menuItemBody.getView().getAssociatedViewBody()).setDefaultHeaders(List.of("meta-title")); + menuItemBody.setAllowedRoles(menuItemService.collectRoles(Map.of("admin", "menu_item"))); + menuItemBody.setBannedRoles(menuItemService.collectRoles(Map.of("system", "menu_item"))); + + Case menuItemCase = menuItemService.createMenuItem(menuItemBody); + + // MENU ITEM + UriNode leafNode = uriService.findByUri("/netgrif/test/new_menu_item"); + assertNotNull(leafNode); + assertEquals(menuItemCase.getUriNodeId(), uriService.findByUri("/netgrif/test").getStringId()); + assertEquals("device_hub", menuItemCase.getFieldValue(MenuItemConstants.FIELD_MENU_ICON)); + I18nString menuName = (I18nString) menuItemCase.getFieldValue(MenuItemConstants.FIELD_MENU_NAME); + assertEquals(new I18nString("new_menu_item"), menuName); + assertEquals("new_menu_item", menuItemCase.getFieldValue(MenuItemConstants.FIELD_IDENTIFIER).toString()); + + Map bannedRolesOptions = menuItemCase.getDataSet().get(MenuItemConstants.FIELD_BANNED_ROLES).getOptions(); + assertTrue(bannedRolesOptions.containsKey("system:menu_item")); + Map allowedRolesOptions = menuItemCase.getDataSet().get(MenuItemConstants.FIELD_ALLOWED_ROLES).getOptions(); + assertTrue(allowedRolesOptions.containsKey("admin:menu_item")); + + // CASE VIEW + assertEquals(true, menuItemCase.getFieldValue(MenuItemConstants.FIELD_USE_TABBED_VIEW)); + assertEquals(MenuItemViewType.CASE_VIEW.getIdentifier(), menuItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE)); + + String caseViewId = MenuItemUtils.getCaseIdFromCaseRef(menuItemCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(caseViewId); + Case caseView = workflowService.findOne(caseViewId); + DataField filterDataField = caseView.getDataField(CaseViewConstants.FIELD_FILTER); + assertEquals("processIdentifier:menu_item", filterDataField.getValue()); + assertEquals(true, caseView.getFieldValue(CaseViewConstants.FIELD_ALL_ALLOWED_NETS)); + assertEquals(true, caseView.getFieldValue(CaseViewConstants.FIELD_INHERIT_ALLOWED_NETS)); + + List caseDefaultHeaders = (List) caseView.getFieldValue(CaseViewConstants.FIELD_DEFAULT_HEADERS); + assertEquals(2, caseDefaultHeaders.size()); + assertTrue(caseDefaultHeaders.containsAll(List.of("meta-title", "meta-processIdentifier"))); + assertEquals(MenuItemViewType.TASK_VIEW.getIdentifier(), caseView.getFieldValue(CaseViewConstants.FIELD_CONFIGURATION_TYPE)); + + // TASK VIEW + String taskViewId = MenuItemUtils.getCaseIdFromCaseRef(caseView, CaseViewConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(taskViewId); + Case taskView = workflowService.findOne(taskViewId); + List taskDefaultHeaders = (List) taskView.getFieldValue(TaskViewConstants.FIELD_DEFAULT_HEADERS); + assertEquals(1, taskDefaultHeaders.size()); + assertTrue(taskDefaultHeaders.contains("meta-title")); + + // FOLDERS + Case testFolder = findMenuItem("test"); + Case netgrifFolder = findMenuItem("netgrif"); + + UriNode testNode = uriService.findByUri("/netgrif"); + UriNode netgrifNode = uriService.getRoot(); + + Case rootFolder = findMenuItem(""); + + assertNotNull(testFolder); + assertNotNull(testNode); + assertEquals(testNode.getStringId(), testFolder.getUriNodeId()); + + String testFolderParentId = MenuItemUtils.getCaseIdFromCaseRef(testFolder, MenuItemConstants.FIELD_PARENT_ID); + assertEquals(netgrifFolder.getStringId(), testFolderParentId); + + List testFolderChildIds = MenuItemUtils.getCaseIdsFromCaseRef(testFolder, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(testFolderChildIds); + assertTrue(testFolderChildIds.contains(menuItemCase.getStringId())); + + String itemParentId = MenuItemUtils.getCaseIdFromCaseRef(menuItemCase, MenuItemConstants.FIELD_PARENT_ID); + assertEquals(testFolder.getStringId(), itemParentId); + + assertEquals(netgrifNode.getStringId(), netgrifFolder.getUriNodeId()); + + String netgrifFolderParentId = MenuItemUtils.getCaseIdFromCaseRef(netgrifFolder, MenuItemConstants.FIELD_PARENT_ID); + assertEquals(rootFolder.getStringId(), netgrifFolderParentId); + + List netgrifFolderChildIds = MenuItemUtils.getCaseIdsFromCaseRef(netgrifFolder, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(netgrifFolderChildIds); + assertTrue(netgrifFolderChildIds.contains(testFolder.getStringId())); + + String rootFolderParentId = MenuItemUtils.getCaseIdFromCaseRef(rootFolder, MenuItemConstants.FIELD_PARENT_ID); + assertNull(rootFolderParentId); + + List rootFolderChildIds = MenuItemUtils.getCaseIdsFromCaseRef(rootFolder, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(rootFolderChildIds); + assertTrue(rootFolderChildIds.contains(netgrifFolder.getStringId())); + } + + @Test + public void updateMenuItemTest() throws TransitionNotExecutableException { + assertThrows(IllegalArgumentException.class, () -> menuItemService.updateMenuItem(null, null)); + + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(SimpleTaskViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri(uriService.getRoot().getUriPath()); + menuItemBody.setIdentifier("test"); + Case menuItemCase = menuItemService.createMenuItem(menuItemBody); + + String oldMenuItemCaseId = menuItemCase.getStringId(); + String oldViewCaseId = MenuItemUtils.getCaseIdFromCaseRef(menuItemCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + Case simpleTaskViewCase = workflowService.findOne(oldViewCaseId); + assertEquals("task_view_configuration", simpleTaskViewCase.getProcessIdentifier()); + assertNull(MenuItemUtils.getCaseIdFromCaseRef(simpleTaskViewCase, ViewConstants.FIELD_VIEW_CONFIGURATION_ID)); + + assertThrows(IllegalArgumentException.class, () -> menuItemService.updateMenuItem(menuItemCase, null)); + assertThrows(IllegalArgumentException.class, () -> menuItemService.updateMenuItem(menuItemCase, new MenuItemBody())); + + menuItemBodyOpt = MenuItemTemplateHolder.get(TabbedCaseViewTemplate.IDENTIFIER, uriService.getRoot().getUriPath(), + "test"); + assertTrue(menuItemBodyOpt.isPresent()); + + Case updatedMenuItemCase = menuItemService.updateMenuItem(menuItemCase, menuItemBodyOpt.get()); + + assertThrows(IllegalArgumentException.class, () -> workflowService.findOne(oldMenuItemCaseId)); + assertThrows(IllegalArgumentException.class, () -> workflowService.findOne(oldViewCaseId)); + + String newMenuItemCaseId = updatedMenuItemCase.getStringId(); + assertNotEquals(oldMenuItemCaseId, newMenuItemCaseId); + String newViewCaseId = MenuItemUtils.getCaseIdFromCaseRef(updatedMenuItemCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotEquals(oldViewCaseId, newViewCaseId); + Case caseViewCase = workflowService.findOne(newViewCaseId); + assertEquals("case_view_configuration", caseViewCase.getProcessIdentifier()); + String taskViewCaseId = MenuItemUtils.getCaseIdFromCaseRef(caseViewCase, ViewConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(taskViewCaseId); + Case taskViewCase = workflowService.findOne(taskViewCaseId); + assertEquals("task_view_configuration", taskViewCase.getProcessIdentifier()); + } + + @Test + public void createOrUpdateMenuItemTest() throws TransitionNotExecutableException { + assertThrows(IllegalArgumentException.class, () -> menuItemService.createOrUpdateMenuItem(null)); + + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(CustomViewTemplate.IDENTIFIER, + uriService.getRoot().getUriPath(), "test"); + assertTrue(menuItemBodyOpt.isPresent()); + + Case firstMenuItemCase = menuItemService.createOrUpdateMenuItem(menuItemBodyOpt.get()); + Case secondMenuItemCase = menuItemService.createOrUpdateMenuItem(menuItemBodyOpt.get()); + + assertNotEquals(firstMenuItemCase.getStringId(), secondMenuItemCase.getStringId()); + assertThrows(IllegalArgumentException.class, () -> workflowService.findOne(firstMenuItemCase.getStringId())); + } + + @Test + public void createOrIgnoreMenuItemTest() throws TransitionNotExecutableException { + assertThrows(IllegalArgumentException.class, () -> menuItemService.createOrIgnoreMenuItem(null)); + + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(CustomViewTemplate.IDENTIFIER, + uriService.getRoot().getUriPath(), "test"); + assertTrue(menuItemBodyOpt.isPresent()); + + Case firstMenuItemCase = menuItemService.createOrIgnoreMenuItem(menuItemBodyOpt.get()); + Case secondMenuItemCase = menuItemService.createOrIgnoreMenuItem(menuItemBodyOpt.get()); + + assertEquals(firstMenuItemCase.getStringId(), secondMenuItemCase.getStringId()); + } + + @Test + public void findMenuItemByIdentifierTest() throws TransitionNotExecutableException { + assertNull(menuItemService.findMenuItem(null)); + assertNull(menuItemService.findMenuItem("wrong")); + + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(CustomViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri(uriService.getRoot().getUriPath()); + String identifier = "test"; + menuItemBody.setIdentifier(identifier); + + Case createdMenuItemCase = menuItemService.createMenuItem(menuItemBody); + Case foundMenuItemCase = menuItemService.findMenuItem(identifier); + assertEquals(createdMenuItemCase.getStringId(), foundMenuItemCase.getStringId()); + } + + @Test + public void findFolderCaseTest() throws TransitionNotExecutableException { + assertThrows(IllegalArgumentException.class, () -> menuItemService.findFolderCase(null)); + assertNull(menuItemService.findFolderCase(new UriNode())); + + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(CustomViewTemplate.IDENTIFIER, "/folderik", "test"); + assertTrue(menuItemBodyOpt.isPresent()); + + Case createdMenuItemCase = menuItemService.createMenuItem(menuItemBodyOpt.get()); + String parentFolderCaseId = MenuItemUtils.getCaseIdFromCaseRef(createdMenuItemCase, MenuItemConstants.FIELD_PARENT_ID); + assertNotNull(parentFolderCaseId); + UriNode node = uriService.findById(createdMenuItemCase.getUriNodeId()); + Case folderCase = menuItemService.findFolderCase(node); + assertEquals(parentFolderCaseId, folderCase.getStringId()); + } + + @Test + public void existsMenuItemTest() throws TransitionNotExecutableException { + assertFalse(menuItemService.existsMenuItem(null)); + assertFalse(menuItemService.existsMenuItem("wrong")); + + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(CustomViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri(uriService.getRoot().getUriPath()); + String identifier = "test"; + menuItemBody.setIdentifier(identifier); + + menuItemService.createMenuItem(menuItemBody); + assertTrue(menuItemService.existsMenuItem(identifier)); + } + + @Test + public void moveItemTest() throws TransitionNotExecutableException { + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(CustomViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri("/netgrif/test"); + menuItemBody.setIdentifier("new_menu_item"); + Case newMenuItemCase = menuItemService.createMenuItem(menuItemBody); + menuItemBody.setUri("/netgrif2/test2"); + menuItemBody.setIdentifier("new_menu_item2"); + Case newMenuItem2Case = menuItemService.createMenuItem(menuItemBody); + + assertThrows(IllegalArgumentException.class, () -> menuItemService.moveItem(null, "/mypath")); + Case finalNewMenuItemCase = newMenuItemCase; + assertThrows(IllegalArgumentException.class, () -> menuItemService.moveItem(finalNewMenuItemCase, null)); + + menuItemService.moveItem(newMenuItemCase, "/netgrif2"); + + newMenuItemCase = workflowService.findOne(newMenuItemCase.getStringId()); + UriNode netgrif2Node = uriService.findByUri("/netgrif2"); + assertEquals(netgrif2Node.getStringId(), newMenuItemCase.getUriNodeId()); + Case netgrif2FolderCase = findMenuItem("netgrif2"); + List netgrif2ChildIds = MenuItemUtils.getCaseIdsFromCaseRef(netgrif2FolderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(netgrif2ChildIds); + assertEquals(2, netgrif2ChildIds.size()); + assertTrue(netgrif2ChildIds.contains(newMenuItemCase.getStringId())); + + Case finalNetgrif2FolderCase = netgrif2FolderCase; + assertThrows(IllegalArgumentException.class, () -> menuItemService.moveItem(finalNetgrif2FolderCase, "/netgrif2/cyclic")); + + menuItemService.moveItem(netgrif2FolderCase, "/netgrif/test3"); + Case test3FolderCase = findMenuItem("test3"); + Case netgrifFolderCase = findMenuItem("netgrif"); + + String test3ParentCaseId = MenuItemUtils.getCaseIdFromCaseRef(test3FolderCase, MenuItemConstants.FIELD_PARENT_ID); + assertNotNull(test3ParentCaseId); + assertEquals(test3ParentCaseId, netgrifFolderCase.getStringId()); + + List netgrifFolderChildIds = MenuItemUtils.getCaseIdsFromCaseRef(netgrifFolderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(netgrifFolderChildIds); + assertTrue(netgrifFolderChildIds.contains(test3FolderCase.getStringId())); + + netgrif2FolderCase = workflowService.findOne(netgrif2FolderCase.getStringId()); + UriNode test3Node = uriService.findByUri("/netgrif/test3"); + assertEquals(test3Node.getStringId(), netgrif2FolderCase.getUriNodeId()); + assertEquals("/netgrif/test3/netgrif2", netgrif2FolderCase.getFieldValue(MenuItemConstants.FIELD_NODE_PATH)); + netgrif2ChildIds = MenuItemUtils.getCaseIdsFromCaseRef(netgrif2FolderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(netgrif2ChildIds); + assertEquals(2, netgrif2ChildIds.size()); + + Case test2FolderCase = findMenuItem("test2"); + netgrif2Node = uriService.findByUri("/netgrif/test3/netgrif2"); + assertEquals(netgrif2Node.getStringId(), test2FolderCase.getUriNodeId()); + assertEquals("/netgrif/test3/netgrif2/test2", test2FolderCase.getFieldValue(MenuItemConstants.FIELD_NODE_PATH)); + + newMenuItem2Case = workflowService.findOne(newMenuItem2Case.getStringId()); + UriNode test2Node = uriService.findByUri("/netgrif/test3/netgrif2/test2"); + assertEquals(test2Node.getStringId(), newMenuItem2Case.getUriNodeId()); + } + + @Test + public void duplicateFolderItemTest() throws TransitionNotExecutableException { + String starterUri = "/netgrif/test"; + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(TabbedCaseViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri(starterUri); + menuItemBody.setIdentifier("new_menu_item"); + menuItemService.createMenuItem(menuItemBody); + Case originFolderCase = findMenuItem("test"); + + String newTitle = "New title"; + String newIdentifier = "new_identifier"; + + String duplicateTaskId = MenuItemUtils.findTaskIdInCase(originFolderCase, "duplicate_item"); + taskService.assignTask(duplicateTaskId); + + originFolderCase.getDataField(MenuItemConstants.FIELD_DUPLICATE_TITLE).setValue(new I18nString("")); + originFolderCase.getDataField(MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER).setValue(newIdentifier); + originFolderCase = workflowService.save(originFolderCase); + assertThrows(IllegalArgumentException.class, () -> taskService.finishTask(duplicateTaskId)); + + originFolderCase.getDataField(MenuItemConstants.FIELD_DUPLICATE_TITLE).setValue(new I18nString(newTitle)); + originFolderCase.getDataField(MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER).setValue("new_menu_item"); + originFolderCase = workflowService.save(originFolderCase); + assertThrows(IllegalArgumentException.class, () -> taskService.finishTask(duplicateTaskId)); + + originFolderCase.getDataField(MenuItemConstants.FIELD_DUPLICATE_TITLE).setValue(new I18nString(newTitle)); + originFolderCase.getDataField(MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER).setValue(newIdentifier); + originFolderCase = workflowService.save(originFolderCase); + taskService.finishTask(duplicateTaskId); + + Case duplicatedFolderCase = findMenuItem(newIdentifier); + assertNotNull(duplicatedFolderCase); + + UriNode leafNode = uriService.findByUri("/netgrif/" + newIdentifier); + + assertNotNull(leafNode); + assertEquals(duplicatedFolderCase.getUriNodeId(), originFolderCase.getUriNodeId()); + assertEquals(new I18nString(""), duplicatedFolderCase.getFieldValue(MenuItemConstants.FIELD_DUPLICATE_TITLE)); + assertEquals("", duplicatedFolderCase.getFieldValue(MenuItemConstants.FIELD_DUPLICATE_IDENTIFIER)); + assertEquals(newTitle, duplicatedFolderCase.getTitle()); + assertEquals(new I18nString(newTitle), duplicatedFolderCase.getFieldValue(MenuItemConstants.FIELD_MENU_NAME)); + assertEquals(newIdentifier, duplicatedFolderCase.getFieldValue(MenuItemConstants.FIELD_IDENTIFIER)); + assertEquals("/netgrif/" + newIdentifier, duplicatedFolderCase.getFieldValue(MenuItemConstants.FIELD_NODE_PATH)); + List duplicatedChildIds = MenuItemUtils.getCaseIdsFromCaseRef(duplicatedFolderCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(duplicatedChildIds); + assertEquals(0, duplicatedChildIds.size()); + assertFalse((Boolean) duplicatedFolderCase.getFieldValue(MenuItemConstants.FIELD_HAS_CHILDREN)); + assertEquals(1, duplicatedFolderCase.getActivePlaces().get("initialized")); + } + + @Test + @SuppressWarnings("unchecked") + public void duplicateLeafItemTest() throws TransitionNotExecutableException { + String starterUri = "/netgrif/test"; + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(TabbedCaseViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri(starterUri); + menuItemBody.setIdentifier("new_menu_item"); + Case originLeafItemCase = menuItemService.createMenuItem(menuItemBody); + + String newTitle = "New title"; + String newIdentifier = "new_identifier"; + + Case duplicatedLeafItemCase = menuItemService.duplicateItem(originLeafItemCase, new I18nString(newTitle), newIdentifier); + assertEquals(duplicatedLeafItemCase.getUriNodeId(), originLeafItemCase.getUriNodeId()); + assertEquals(duplicatedLeafItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE), + originLeafItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE)); + + String duplicatedCaseViewId = MenuItemUtils.getCaseIdFromCaseRef(duplicatedLeafItemCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(duplicatedCaseViewId); + String originCaseViewId = MenuItemUtils.getCaseIdFromCaseRef(originLeafItemCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(originCaseViewId); + assertNotEquals(duplicatedCaseViewId, originCaseViewId); + + List duplicatedFormValue = (List) duplicatedLeafItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_FORM); + assertNotNull(duplicatedFormValue); + assertEquals(1, duplicatedFormValue.size()); + List originFormValue = (List) originLeafItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_FORM); + assertNotNull(originFormValue); + assertEquals(1, originFormValue.size()); + assertNotEquals(duplicatedFormValue.get(0), originFormValue.get(0)); + + List duplicatedAllFormValue = (List) duplicatedLeafItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM); + assertNotNull(duplicatedAllFormValue); + assertEquals(1, duplicatedAllFormValue.size()); + List originAllFormValue = (List) originLeafItemCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM); + assertNotNull(originAllFormValue); + assertEquals(1, originAllFormValue.size()); + assertNotEquals(duplicatedAllFormValue.get(0), originAllFormValue.get(0)); + + Case duplicatedCaseViewCase = workflowService.findOne(duplicatedCaseViewId); + Case originCaseViewCase = workflowService.findOne(originCaseViewId); + assertEquals(duplicatedCaseViewCase.getProcessIdentifier(), originCaseViewCase.getProcessIdentifier()); + + assertEquals(duplicatedCaseViewCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE), + originCaseViewCase.getFieldValue(MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE)); + + String duplicatedTaskViewId = MenuItemUtils.getCaseIdFromCaseRef(duplicatedCaseViewCase, ViewConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(duplicatedTaskViewId); + String originTaskViewId = MenuItemUtils.getCaseIdFromCaseRef(originCaseViewCase, ViewConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(originTaskViewId); + assertNotEquals(duplicatedTaskViewId, originTaskViewId); + } + + @Test + public void removeChildItemFromParentTest() throws TransitionNotExecutableException { + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(CustomViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri("/folderik"); + menuItemBody.setIdentifier("test"); + + Case testItemCase = menuItemService.createMenuItem(menuItemBody); + + Case folderikCase = findMenuItem("folderik"); + assertNotNull(folderikCase); + List childrenCaseIds = MenuItemUtils.getCaseIdsFromCaseRef(folderikCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(childrenCaseIds); + assertEquals(1, childrenCaseIds.size()); + assertTrue(childrenCaseIds.contains(testItemCase.getStringId())); + assertTrue((Boolean) folderikCase.getFieldValue(MenuItemConstants.FIELD_HAS_CHILDREN)); + + folderikCase = menuItemService.removeChildItemFromParent(folderikCase.getStringId(), testItemCase); + + childrenCaseIds = MenuItemUtils.getCaseIdsFromCaseRef(folderikCase, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(childrenCaseIds); + assertEquals(0, childrenCaseIds.size()); + assertFalse((Boolean) folderikCase.getFieldValue(MenuItemConstants.FIELD_HAS_CHILDREN)); + } + + @Test + public void getMenuItemDataTest() throws TransitionNotExecutableException { + assertThrows(IllegalArgumentException.class, () -> menuItemService.getMenuItemData("wrongCaseId", Locale.getDefault())); + + Case menuItemCase = createDefaultMenuItem("my_menu_item", + new I18nString("This is name", Map.of("sk", "Toto je nazov"))); + + login(); + List result = menuItemService.getMenuItemData(menuItemCase.getStringId(), Locale.getDefault()); + assertTrue(result != null && !result.isEmpty()); + } + + @Test + @SuppressWarnings("unchecked") + public void handleConfigurationTemplateTest() throws TransitionNotExecutableException { + Case menuItemCase = workflowService.createCaseByIdentifier(MenuItemConstants.PROCESS_IDENTIFIER, "", "", + userService.getSystem().transformToLoggedUser()).getCase(); + + menuItemCase = dataService.setData(MenuItemUtils.findTaskIdInCase(menuItemCase, MenuItemConstants.TRANS_INIT_ID), + ImportHelper.populateDataset( + Map.of(MenuItemConstants.FIELD_CONFIGURATION_TEMPLATES, + Map.of("type", FieldType.ENUMERATION_MAP.getName(), "value", TabbedCaseViewTemplate.IDENTIFIER)) + ) + ).getCase(); + + ConfigurationTemplateOutcome outcome = menuItemService.handleConfigurationTemplate(menuItemCase); + + assertTrue((Boolean) outcome.getMapping().get(MenuItemConstants.FIELD_USE_TABBED_VIEW)); + assertFalse((Boolean) outcome.getMapping().get(MenuItemConstants.FIELD_USE_CUSTOM_VIEW)); + assertEquals(MenuItemViewType.CASE_VIEW.getIdentifier(), outcome.getMapping().get(MenuItemConstants.FIELD_VIEW_CONFIGURATION_TYPE)); + List viewCaseIdAsList = (List) outcome.getMapping().get(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertEquals(1, viewCaseIdAsList.size()); + Case viewCase = workflowService.findOne(viewCaseIdAsList.get(0)); + assertEquals("case_view_configuration", viewCase.getProcessIdentifier()); + List viewFormTaskIdAsList = (List) outcome.getMapping().get(MenuItemConstants.FIELD_VIEW_CONFIGURATION_FORM); + assertEquals(1, viewFormTaskIdAsList.size()); + assertEquals(MenuItemUtils.findTaskIdInCase(viewCase, ViewConstants.TRANS_SETTINGS_ID), viewFormTaskIdAsList.get(0)); + List viewAllFormTaskIdAsList = (List) outcome.getMapping().get(MenuItemConstants.FIELD_VIEW_CONFIGURATION_ALL_DATA_FORM); + assertEquals(1, viewAllFormTaskIdAsList.size()); + assertEquals(MenuItemUtils.findTaskIdInCase(viewCase, ViewConstants.TRANS_ALL_MENU_DATA_ID), viewAllFormTaskIdAsList.get(0)); + } + + @Test + public void getAvailableViewsAsOptionsByIsPrimaryTest() { + + Map options = menuItemService.getAvailableViewsAsOptions(true, true); + assertNotNull(options); + assertEquals(4, options.size()); + assertTrue(options.containsKey(MenuItemViewType.CASE_VIEW.getIdentifier())); + assertTrue(options.containsKey(MenuItemViewType.TASK_VIEW.getIdentifier())); + assertTrue(options.containsKey(MenuItemViewType.TABBED_TICKET_VIEW.getIdentifier())); + assertTrue(options.containsKey(MenuItemViewType.SINGLE_TASK_VIEW.getIdentifier())); + + options = menuItemService.getAvailableViewsAsOptions(true, false); + assertNotNull(options); + assertEquals(0, options.size()); + + options = menuItemService.getAvailableViewsAsOptions(false, false); + assertNotNull(options); + assertEquals(0, options.size()); + + options = menuItemService.getAvailableViewsAsOptions(false, true); + assertNotNull(options); + assertEquals(3, options.size()); + assertTrue(options.containsKey(MenuItemViewType.CASE_VIEW.getIdentifier())); + assertTrue(options.containsKey(MenuItemViewType.TASK_VIEW.getIdentifier())); + assertTrue(options.containsKey(MenuItemViewType.SINGLE_TASK_VIEW.getIdentifier())); + } + + @Test + public void getAvailableViewsAsOptionsByViewIdentifierTest() { + Map options = menuItemService.getAvailableViewsAsOptions(true, MenuItemViewType.CASE_VIEW.getIdentifier()); + assertNotNull(options); + assertEquals(1, options.size()); + assertTrue(options.containsKey(MenuItemViewType.TASK_VIEW.getIdentifier())); + + options = menuItemService.getAvailableViewsAsOptions(true, MenuItemViewType.TABBED_TICKET_VIEW.getIdentifier()); + assertNotNull(options); + assertEquals(1, options.size()); + assertTrue(options.containsKey(MenuItemViewType.SINGLE_TASK_VIEW.getIdentifier())); + + options = menuItemService.getAvailableViewsAsOptions(false, MenuItemViewType.TABBED_TICKET_VIEW.getIdentifier()); + assertNotNull(options); + assertEquals(1, options.size()); + assertTrue(options.containsKey(MenuItemViewType.SINGLE_TASK_VIEW.getIdentifier())); + + options = menuItemService.getAvailableViewsAsOptions(true, MenuItemViewType.TASK_VIEW.getIdentifier()); + assertNotNull(options); + assertEquals(0, options.size()); + } + + @Test + void testRemoveMenuItem() throws TransitionNotExecutableException, InterruptedException { + Optional menuItemBodyOpt = MenuItemTemplateHolder.get(TabbedCaseViewTemplate.IDENTIFIER); + assertTrue(menuItemBodyOpt.isPresent()); + MenuItemBody menuItemBody = menuItemBodyOpt.get(); + menuItemBody.setUri("/netgrif/test"); + menuItemBody.setIdentifier("new_menu_item"); + Case leafItemCase = menuItemService.createMenuItem(menuItemBody); + + Case testFolder = findMenuItem("test"); + String netgrifFolderId = MenuItemUtils.getCaseIdFromCaseRef(testFolder, MenuItemConstants.FIELD_PARENT_ID); + + Case netgrifFolder = workflowService.findOne(netgrifFolderId); + List childIds = MenuItemUtils.getCaseIdsFromCaseRef(netgrifFolder, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(childIds); + assertTrue(childIds.contains(testFolder.getStringId())); + assertDoesNotThrow(() -> workflowService.findOne(testFolder.getStringId())); + assertDoesNotThrow(() -> workflowService.findOne(leafItemCase.getStringId())); + String tabbedCaseViewId = MenuItemUtils.getCaseIdFromCaseRef(leafItemCase, MenuItemConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(tabbedCaseViewId); + Case tabbedCaseView = workflowService.findOne(tabbedCaseViewId); + String tabbedTaskViewId = MenuItemUtils.getCaseIdFromCaseRef(tabbedCaseView, CaseViewConstants.FIELD_VIEW_CONFIGURATION_ID); + assertNotNull(tabbedTaskViewId); + assertDoesNotThrow(() -> workflowService.findOne(tabbedTaskViewId)); + + workflowService.deleteCase(testFolder); + Thread.sleep(2000); + netgrifFolder = workflowService.findOne(netgrifFolderId); + List updatedChildIds = MenuItemUtils.getCaseIdsFromCaseRef(netgrifFolder, MenuItemConstants.FIELD_CHILD_ITEM_IDS); + assertNotNull(updatedChildIds); + assertFalse(updatedChildIds.contains(testFolder.getStringId())); + assertThrows(IllegalArgumentException.class, () -> workflowService.findOne(testFolder.getStringId())); + assertThrows(IllegalArgumentException.class, () -> workflowService.findOne(leafItemCase.getStringId())); + assertThrows(IllegalArgumentException.class, () -> workflowService.findOne(tabbedCaseViewId)); + assertThrows(IllegalArgumentException.class, () -> workflowService.findOne(tabbedTaskViewId)); + } + + private Case createDefaultMenuItem(String identifier, I18nString name) throws TransitionNotExecutableException { + FilterBody filterBody = new FilterBody(); + filterBody.setQuery("processIdentifier:process1"); + filterBody.setType(FieldType.CASE_FILTER); + + CaseViewBody caseView = new CaseViewBody(); + caseView.setFilterBody(filterBody); + caseView.setRequireTitleInCreation(false); + caseView.setChainedView(new TaskViewBody()); + + MenuItemBody menuItemBody = new MenuItemBody(); + menuItemBody.setUri("/"); + menuItemBody.setIdentifier(identifier); + menuItemBody.setMenuIcon("home"); + menuItemBody.setMenuName(name); + menuItemBody.setTabIcon("folder"); + menuItemBody.setTabName(name); + menuItemBody.setView(caseView); + + return menuItemService.createMenuItem(menuItemBody); + } + + private void login() { + SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(superCreator.getLoggedSuper(), null)); + } + + private String getTaskId(Case useCase, String transId) { + return useCase.getTasks().stream() + .filter((taskPair -> taskPair.getTransition().equals(transId))) + .map(TaskPair::getTask) + .findFirst().orElse(null); + } + + private Case findMenuItem(String identifier) { + Query query = Query.query( + Criteria.where("processIdentifier").is(MenuItemConstants.PROCESS_IDENTIFIER) + .and(String.format("dataSet.%s.value", MenuItemConstants.FIELD_IDENTIFIER)).is(identifier) + ); + query.withHint(MenuItemConstants.IDENTIFIER_INDEX_NAME); + List caseAsList = mongoTemplate.find(query, Case.class); + Optional caseOptional = caseAsList.stream().findFirst(); + return caseOptional.map(aCase -> workflowService.findOne(aCase.getStringId())).orElse(null); + } +} diff --git a/src/test/resources/dashboard_management_test.xml b/src/test/resources/dashboard_management_test.xml index d3f1ae15906..199b8a68b98 100644 --- a/src/test/resources/dashboard_management_test.xml +++ b/src/test/resources/dashboard_management_test.xml @@ -27,7 +27,7 @@ filterBody.getTitle(), filterBody.getIcon() ) - def singleTaskViewBody = new com.netgrif.application.engine.menu.domain.configurations.TabbedSingleTaskViewBody() + def singleTaskViewBody = new com.netgrif.application.engine.menu.domain.configurations.SingleTaskViewBody() def ticketViewBody = new com.netgrif.application.engine.menu.domain.configurations.TabbedTicketViewBody() ticketViewBody.setChainedView(singleTaskViewBody) menuItemBody.setAutoSelect(true) diff --git a/src/test/resources/petriNets/filter_api_test.xml b/src/test/resources/petriNets/filter_api_test.xml deleted file mode 100644 index ab00d976034..00000000000 --- a/src/test/resources/petriNets/filter_api_test.xml +++ /dev/null @@ -1,258 +0,0 @@ - - filter_api_test - FTT - filter_api_test - device_hub - true - true - false - - - role_1 - Role 1 - - - - role_2 - Role 2 - - - - - upload - - - createCase("filter_api_test") - - - - - - - - menu_stringId - - </data> - <data type="text"> - <id>filter_stringId</id> - <title/> - </data> - - <data type="text"> - <id>query</id> - <title/> - <init>processIdentifier:"filter_api_test"</init> - </data> - <data type="text"> - <id>icon</id> - <title/> - <init>device_hub</init> - </data> - <data type="text"> - <id>uri</id> - <title/> - </data> - <data type="text"> - <id>allowed_nets</id> - <title/> - </data> - <data type="text"> - <id>title</id> - <title/> - </data> - <data type="text"> - <id>identifier</id> - <title/> - </data> - <data type="text"> - <id>group</id> - <title>Skupina - - - - create_filter_and_menu - create filter and menu - - - - - menu_stringId: f.menu_stringId, - filter_stringId: f.filter_stringId, - uri: f.uri, - title: f.title, - allowed_nets: f.allowed_nets, - query: f.query, - identifier: f.identifier, - icon: f.icon; - - def filter = createCaseFilter(title.value, query.value, allowed_nets.value.split(",") as List, icon.value) - def item = createMenuItem(uri.value, identifier.value, title.value, icon.value, filter, - ["role_1": "filter_api_test"], ["role_2": "filter_api_test"], - ["meta-title,meta-title"], ["meta-title,meta-title"]) - - change menu_stringId value { item.stringId } - change filter_stringId value { filter.stringId } - - - - - - change_filter_and_menu - change filter and menu - - - - - uri: f.uri, - title: f.title, - allowed_nets: f.allowed_nets, - query: f.query, - identifier: f.identifier, - icon: f.icon; - - def metadata = [ - "searchCategories" : [], - "predicateMetadata" : [], - "filterType" : type, - "defaultSearchCategories": false, - "inheritAllowedNets" : false - ] - createOrUpdateMenuItemAndFilter(uri.value, identifier.value, title.value, query.value, "Case", - "private", allowed_nets.value.split(",") as List, icon.value, ["role_2": "filter_api_test"], - [:], ["meta-title","meta-title","meta-title"], ["meta-title","meta-title","meta-title"], metadata) - - - - - - delete_filter_and_menu - delete filter and menu - - - - - menu_stringId: f.menu_stringId, - identifier: f.identifier; - - def item = workflowService.findOne(menu_stringId.value) - def filter = getFilterFromMenuItem(item) - - deleteMenuItem(item) - deleteFilter(filter) - - - - - - create_filter_in_group - create filter in group - - - - - menu_stringId: f.menu_stringId, - filter_stringId: f.filter_stringId, - uri: f.uri, - title: f.title, - allowed_nets: f.allowed_nets, - query: f.query, - group: f.group, - identifier: f.identifier, - icon: f.icon; - - def item = createFilterInMenu( - uri.value, - identifier.value, - title.value, - query.value, - type.value, - allowed_nets.value.split(",") as List, - ["role_1": "filter_api_test"], - [:], - icon.value - ) - def filter = getFilterFromMenuItem(item) - - change menu_stringId value { item.stringId } - change filter_stringId value { filter.stringId } - - - - - - - find_filter - find filter - - - - - title: f.title, - found_filter: f.found_filter; - - def filter = findFilter(title.value) - change found_filter value { filter.stringId } - - - - - - found_filter - found filter - - - - move_item - move item - - - - move_dest_uri: f.move_dest_uri, - move_item_id: f.move_item_id, - move_folder_path: f.move_folder_path; - - def item - if (move_item_id.value) { - item = workflowService.findOne(move_item_id.value) - } else if (move_folder_path.value) { - def node = uriService.findByUri(move_folder_path.value) - item = findFolderCase(node) - } - - moveMenuItem(item, move_dest_uri.value) - - - - - - move_dest_uri - found filter - - - move_item_id - View item id to find - - - move_folder_path - Folder item path to find - - - - t1 - 700 - 180 - - - t1_assign - - - t1_finish - - - t1_cancel - - - t1_delegate - - - \ No newline at end of file diff --git a/src/test/resources/petriNets/filter_test.xml b/src/test/resources/petriNets/filter_test.xml new file mode 100644 index 00000000000..6719cb47bb9 --- /dev/null +++ b/src/test/resources/petriNets/filter_test.xml @@ -0,0 +1,68 @@ + + filter_test + FTT + filter_test + device_hub + true + false + false + + + filter_field + + <init>someQueryString</init> + </data> + + <data type="caseFilter"> + <id>case_filter_field</id> + <title/> + <init>someQueryString</init> + </data> + + <data type="taskFilter"> + <id>task_filter_field</id> + <title/> + <init>someQueryString</init> + </data> + + <data type="processFilter"> + <id>process_filter_field</id> + <title/> + <init>someQueryString</init> + </data> + + <transition> + <id>t1</id> + <x>700</x> + <y>180</y> + <label>test</label> + <dataGroup> + <id>t1_0</id> + <layout>legacy</layout> + <dataRef> + <id>filter_field</id> + <logic> + <behavior>editable</behavior> + </logic> + </dataRef> + <dataRef> + <id>case_filter_field</id> + <logic> + <behavior>editable</behavior> + </logic> + </dataRef> + <dataRef> + <id>task_filter_field</id> + <logic> + <behavior>editable</behavior> + </logic> + </dataRef> + <dataRef> + <id>process_filter_field</id> + <logic> + <behavior>editable</behavior> + </logic> + </dataRef> + </dataGroup> + </transition> +</document> \ No newline at end of file