67 Commits

Author SHA1 Message Date
f456e278cb Update dependencies and bump version 2023-10-02 12:15:52 +02:00
f28ab1afcd Do not sort by form name in first place for now 2023-10-02 12:09:54 +02:00
ae6b8d48e5 Merge pull request #9 from CCC-MF/issue_8
Issue #8: Add sorting by depency for required form references and subforms
2023-09-30 16:27:13 +02:00
1302963b56 Issue #8: Use system library content as equal content
Since system library content is already present in OS database, it is no dependencies to be imported.
2023-09-30 16:09:36 +02:00
6be11a8951 Issue #8: Use field ReferencedDataForm instead of Name 2023-09-30 15:37:09 +02:00
416204b30a Issue #8: Add initial sorting based on form dependencies 2023-09-30 15:06:24 +02:00
86e988c50e Add information about filter option 2023-09-30 13:48:06 +02:00
76de86b685 Add information about dependency and requirement symbols 2023-09-30 13:34:41 +02:00
d0de76770f Sort dependencies and requirements 2023-09-30 13:26:25 +02:00
8cae6ce706 Cleanup Requirement::to_string() 2023-09-30 13:04:47 +02:00
81a0c6204b Move common implementation into Requires trait 2023-09-30 12:11:14 +02:00
21e31f35d1 Change requirement string mapping to match Unterformular implementation 2023-09-30 12:04:45 +02:00
108aae329c Change symbol for subform 2023-09-30 11:58:21 +02:00
1f51d3e994 Show subform entries in tree subcommand 2023-09-28 17:19:14 +02:00
c514005182 Update YAML file for UKM 2023-09-28 02:25:26 +02:00
a127133ba2 Add YAML file for master profile 2023-09-28 00:00:43 +02:00
e2d4d71063 Bump version 2023-09-19 17:38:57 +02:00
629cc8aba9 Merge pull request #7 from CCC-MF/issue_5
Add all required and optional assets into deb package
2023-09-19 17:34:57 +02:00
298a142586 Merge pull request #6 from CCC-MF/issue_4
Skip serializing None option
2023-09-19 17:34:19 +02:00
9b9a0b4622 Add all required and optional assets into deb package 2023-09-19 17:32:49 +02:00
9ffc0783ff Skip serializing None option 2023-09-19 17:31:28 +02:00
771d99fa27 Add extended description for deb packages 2023-09-19 16:54:48 +02:00
eadf9326d0 Update dependencies and mark as v0.4.0 2023-09-19 16:54:48 +02:00
bf63d93efa Add optional field 'Kontaktliste' to forms 2023-09-19 16:54:48 +02:00
ce52f92a7f Fix build error if dir "completion" does not exist 2023-09-11 18:32:31 +02:00
b3054f971e Package deb package containing bash completion 2023-09-04 17:46:55 +02:00
e27d31a8bf Use clap crate in version 4.4 2023-09-04 16:51:22 +02:00
d30c2991c0 Filter printed elements for list and tree sub command 2023-09-04 13:24:28 +02:00
ce8dca1c10 Use --sorted and --strip as options for productive use
This will keep old experimental options as alias.
2023-09-04 13:04:44 +02:00
bfa7cc3c6b Add sub command to calculate sha256 sum of an OSC file 2023-09-03 18:49:28 +02:00
9256e242eb Allow (actual) unused option 2023-09-03 18:40:43 +02:00
e33b1a3a4c Do not list form references twice as dataform and unterformular 2023-09-03 18:14:06 +02:00
42cbb9ce7e Combine matches to produce the same string 2023-09-03 18:06:56 +02:00
8edd50feb4 Show form references using tree sub command 2023-09-03 17:31:38 +02:00
31eda3efc9 Show notice if form has no field to be used as procedure date
This indicates that the form cannot be used as main form, but as subform only.
2023-09-03 14:03:31 +02:00
54cea88486 Inline additional information about subform mark 2023-09-03 13:58:28 +02:00
4040c49521 Update link to example files 2023-09-01 19:50:25 +02:00
e0b16c16d4 Remove xml-rs and update dependencies 2023-09-01 19:50:22 +02:00
c07d4c8976 Merge pull request #3 from CCC-MF/hide_form_fields
Hide form fields in OSC file using profile configuration
2023-09-01 12:40:13 +02:00
3ec51099c7 Extract method to apply form field profile part 2023-09-01 12:31:48 +02:00
1e7a95bb09 Always save form field content for hidden form fields 2023-09-01 09:07:08 +02:00
abdef90e90 Set filter to "false" if form field should be hidden 2023-08-31 22:20:19 +02:00
a2df2650ed Use empty entry lists if they did not exist in file 2023-08-31 17:30:47 +02:00
f947395c54 Update dependencies 2023-08-31 17:00:32 +02:00
d3d4ec2646 Add a section for experimental functions in README.md 2023-08-31 17:00:00 +02:00
f507893b4d Show required dependencies not included in OSC file 2023-08-31 16:46:40 +02:00
af4ec8898a Strip content that is included in system library 2023-08-31 16:10:19 +02:00
7d6a6ee9b3 Add information about user library flag 2023-08-31 15:54:38 +02:00
a605018176 Do not modify forms included in system library 2023-08-31 12:08:34 +02:00
a8851c5e4f Mark system library content 2023-08-31 11:32:51 +02:00
0b0188bd30 Print info_xml content if using diff sub command 2023-08-30 17:57:53 +02:00
1e553aad58 Add add line break to very long argument description 2023-08-30 17:57:44 +02:00
f9c66cfdb1 Merge pull request #2 from CCC-MF/show_requirements
Add sub command 'tree' to show dependencies
2023-08-29 17:38:51 +02:00
103075ab78 Add sub command 'tree' to show dependencies 2023-08-29 17:34:02 +02:00
37c8b47d1f Update dependencies 2023-08-25 20:53:05 +02:00
d83fa34adb Update version and added deb package config 2023-08-07 15:50:16 +02:00
5c91e4d10f Merge pull request #1 from CCC-MF/sorted_export
Sorted export
2023-08-07 14:20:12 +02:00
e84a39b7c4 Apply exported sorting to items itself and nested items 2023-08-07 14:16:44 +02:00
376bfb2852 Experimental sort of exported content 2023-08-07 10:11:45 +02:00
ad35b99371 Update dependencies 2023-08-06 21:37:10 +02:00
224a7dba27 Update dependencies 2023-08-02 12:56:15 +02:00
62ab073cfa Fix error in README.md, showing wrong example command 2023-07-29 13:40:36 +02:00
b2adb3c5fe Add install task to Makefile 2023-07-03 01:15:15 +02:00
a8911f86dd Update dependencies 2023-07-02 23:14:19 +02:00
b030ce6a53 Add subcommand 'diff' to compare two OSC files 2023-07-01 17:40:04 +02:00
b04ee563f2 Update dependencies 2023-07-01 11:57:33 +02:00
6e266feaf5 Changes in UKM profile: Added more form field settings 2023-06-28 10:39:36 +02:00
18 changed files with 1809 additions and 126 deletions

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.idea/* .idea/*
/target /target
/completion
*.iml *.iml

337
Cargo.lock generated
View File

@@ -2,51 +2,117 @@
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3 version = 3
[[package]]
name = "addr2line"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
dependencies = [
"gimli",
]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]] [[package]]
name = "anstyle" name = "anstyle"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
[[package]]
name = "async-trait"
version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "backtrace"
version = "0.3.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
dependencies = [
"addr2line",
"cc",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
]
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]]
name = "bytes"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
[[package]]
name = "cc"
version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0"
dependencies = [
"libc",
]
[[package]]
name = "cfg-if"
version = "1.0.0" version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.3.4" version = "4.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80672091db20273a15cf9fdd4e47ed43b5091ec9841bf4c6145c9dfbbcae09ed" checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
"once_cell",
] ]
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.3.4" version = "4.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1458a1df40e1e2afebb7ab60ce55c1fa8f431146205aa5f4887e0b111c27636" checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"bitflags",
"clap_lex", "clap_lex",
] ]
[[package]] [[package]]
name = "clap_derive" name = "clap_complete"
version = "4.3.2" version = "4.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" checksum = "e3ae8ba90b9d8b007efe66e55e48fb936272f5ca00349b5b0e89877520d35ea7"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@@ -56,9 +122,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.5.0" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]] [[package]]
name = "console" name = "console"
@@ -73,6 +139,35 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "cpufeatures"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
dependencies = [
"libc",
]
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]] [[package]]
name = "encode_unicode" name = "encode_unicode"
version = "0.3.6" version = "0.3.6"
@@ -80,10 +175,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
[[package]] [[package]]
name = "hashbrown" name = "equivalent"
version = "0.12.3" version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "gimli"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
[[package]]
name = "hashbrown"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
[[package]] [[package]]
name = "heck" name = "heck"
@@ -92,20 +209,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]] [[package]]
name = "indexmap" name = "hex"
version = "1.9.3" version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "indexmap"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
dependencies = [ dependencies = [
"autocfg", "equivalent",
"hashbrown", "hashbrown",
] ]
[[package]] [[package]]
name = "itoa" name = "itoa"
version = "1.0.6" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
@@ -115,48 +238,67 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.146" version = "0.2.148"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]] [[package]]
name = "once_cell" name = "miniz_oxide"
version = "1.18.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
dependencies = [
"adler",
]
[[package]]
name = "object"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "osc-variant" name = "osc-variant"
version = "0.1.0" version = "0.5.0"
dependencies = [ dependencies = [
"clap", "clap",
"clap_complete",
"console", "console",
"quick-xml", "quick-xml",
"serde", "serde",
"serde_yaml", "serde_yaml",
"xml-rs", "sha256",
] ]
[[package]] [[package]]
name = "proc-macro2" name = "pin-project-lite"
version = "1.0.60" version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
[[package]]
name = "proc-macro2"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quick-xml" name = "quick-xml"
version = "0.28.2" version = "0.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ce5e73202a820a31f8a0ee32ada5e21029c81fd9e3ebf668a40832e4219d9d1" checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956"
dependencies = [ dependencies = [
"memchr", "memchr",
"serde", "serde",
@@ -164,33 +306,39 @@ dependencies = [
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.28" version = "1.0.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "ryu" name = "rustc-demangle"
version = "1.0.13" version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "ryu"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.164" version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.164" version = "1.0.188"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -199,9 +347,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.9.21" version = "0.9.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9d684e3ec7de3bf5466b32bd75303ac16f0736426e5a4e0d6e489559ce1249c" checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"itoa", "itoa",
@@ -211,10 +359,34 @@ dependencies = [
] ]
[[package]] [[package]]
name = "syn" name = "sha2"
version = "2.0.18" version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha256"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386"
dependencies = [
"async-trait",
"bytes",
"hex",
"sha2",
"tokio",
]
[[package]]
name = "syn"
version = "2.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -222,22 +394,45 @@ dependencies = [
] ]
[[package]] [[package]]
name = "unicode-ident" name = "tokio"
version = "1.0.9" version = "1.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9"
dependencies = [
"backtrace",
"bytes",
"pin-project-lite",
]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]] [[package]]
name = "unicode-width" name = "unicode-width"
version = "0.1.10" version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]] [[package]]
name = "unsafe-libyaml" name = "unsafe-libyaml"
version = "0.2.8" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1865806a559042e51ab5414598446a5871b561d21b6764f2eabb0dd481d880a6" checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
@@ -304,9 +499,3 @@ name = "windows_x86_64_msvc"
version = "0.42.2" version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "xml-rs"
version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52839dc911083a8ef63efa4d039d1f58b5e409f923e44c80828f206f66e5541c"

View File

@@ -1,15 +1,25 @@
[package] [package]
name = "osc-variant" name = "osc-variant"
version = "0.1.0" version = "0.5.0"
edition = "2021" edition = "2021"
authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"]
description = "Anwendung zum Anpassen einer OSC-Datei an einen Standort"
license = "MIT"
readme = "README.md"
build = "build.rs"
[dependencies] [dependencies]
clap = { version = "4.3", features = ["std", "help", "usage", "derive", "error-context" ], default-features = false } clap = { version = "4.4", features = ["std", "help", "usage", "derive", "error-context"], default-features = false }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.9" serde_yaml = "0.9"
quick-xml = { version = "0.28", features = ["escape-html", "serialize"], default-features=false } quick-xml = { version = "0.30", features = ["escape-html", "serialize"], default-features = false }
xml-rs = "0.8"
console = "0.15" console = "0.15"
sha256 = "1.4"
[build-dependencies]
clap = { version = "4.4", features = ["std", "help", "usage", "derive", "error-context"], default-features = false }
clap_complete = "4.4"
[profile.release] [profile.release]
opt-level = "s" opt-level = "s"
@@ -17,3 +27,11 @@ codegen-units = 1
lto = "thin" lto = "thin"
strip = true strip = true
panic = "abort" panic = "abort"
[package.metadata.deb]
copyright = "Copyright (c) 2023 Comprehensive Cancer Center Mainfranken"
extended-description = "Anwendung zum Anpassen einer OSC-Datei an einen Standort."
assets = [
["target/release/osc-variant", "usr/bin/", "755"],
["completion/osc-variant.bash", "etc/bash_completion.d/", "644"]
]

View File

@@ -38,9 +38,13 @@ win-binary-x86_64:
linux-binary-x86_64: linux-binary-x86_64:
cargo build --release --target=x86_64-unknown-linux-gnu cargo build --release --target=x86_64-unknown-linux-gnu
.PHONE: clean .PHONY: install
install:
cargo install --path .
.PHONY: clean
clean: clean:
cargo clean cargo clean
rm -rf osc-variant 2>/dev/null || true rm -rf osc-variant 2>/dev/null || true
rm *_win64.zip 2>/dev/null || true rm *_win64.zip 2>/dev/null || true
rm *_linux.tar.gz 2>/dev/null || true rm *_linux.tar.gz 2>/dev/null || true

View File

@@ -16,12 +16,67 @@ unvollständigen Ausgabedateien zu erzeugen.
### Beispiele ### Beispiele
Die folgenden Unterbefehle sind verfügbar
#### `sha256sum`
Das Berechnen der SHA256 Prüfsumme ist mit dem Unterbefehl `sha256sum` auch unter Windows einfach möglich
und erzeugt eine Ausgabe analog dem Befehl auf Linux-Systemen:
```
osc-variant sha256sum meine-beispieldatei.osc
```
#### `list`
Zum Auflisten der Inhalte einer Datei wird folgender Befehl verwendet: Zum Auflisten der Inhalte einer Datei wird folgender Befehl verwendet:
``` ```
osc-variant list meine-beispieldatei.osc osc-variant list meine-beispieldatei.osc
``` ```
Mit der Option `--filter` kann die Ausgabe eingeschränkt werden.
#### `tree`
Zum Auflisten der Inhalte mit allen Abhängigkeiten, z.B. Daten- und Merkmalskataloge und bei Formularen wird der Befehl
`tree` verwendet:
```
osc-variant tree meine-beispieldatei.osc
```
Abhängigkeiten werden je nach Art gekennzeichnet:
* `+`: Datenkatalog
* `-`: Merkmalskatalog
* `>`: Formularverweis
* `*`: Unterformular
Für Formularverweise und Unterformulare werden dabei die verwendeten Datenkataloge nicht erneut ausgegeben.
Achtung! Dies erzeugt eine sehr umfangreiche Ausgabe.
Mit der Option `--filter` kann auch hier die Ausgabe eingeschränkt werden.
#### `diff`
Zum Vergleich zweier OSC-Dateien wird der Unterbefehl `diff` verwendet.
Der optionale Parameter `--strict` vergleicht auch den Inhalt der OSC-Datei.
Ohne diesen wird nur das Vorhandensein von Inhalten und die Revision verglichen.
```
osc-variant diff meine-beispieldatei.osc andere-beispieldatei.osc
```
bzw.
```
osc-variant diff meine-beispieldatei.osc andere-beispieldatei.osc --strict
```
#### `modify`
Zum Anpassen des Inhalts einer Datei: Zum Anpassen des Inhalts einer Datei:
``` ```
@@ -39,11 +94,31 @@ Ohne eine Angabe der Ausgabedatei wird auf die Standardausgabe ausgegeben.
OSC-Dateien sind XML-Dateien. Diese Anwendung ermöglicht optional die Ausgabe als kompaktere XML-Datei ohne Zeilenumbrüche. OSC-Dateien sind XML-Dateien. Diese Anwendung ermöglicht optional die Ausgabe als kompaktere XML-Datei ohne Zeilenumbrüche.
Hierzu ist die Option `--compact` vorgesehen. Es können, je nach Datei, bis zu 30% eingespart werden. Hierzu ist die Option `--compact` vorgesehen. Es können, je nach Datei, bis zu 30% eingespart werden.
#### Filter
Bei der Auflistung von Inhalten ist es möglich, die Anzeige für die Unterbefehle `list` und `tree` anhand des Namens zu filtern.
Hierzu ist die Option `--filter=` vorgesehen.
Wird diese angewendet, werden nur Inhalte angezeigt, deren Name die angegebene Zeichenkette beinhalten.
#### Sortierung #### Sortierung
Bei der Auflistung der Inhalte, kann die Option `--sorted` dazu verwendet werden, die angezeigten Einträge alphabetisch zu sortieren. Bei der Auflistung der Inhalte, kann die Option `--sorted` dazu verwendet werden, die angezeigten Einträge alphabetisch zu sortieren.
Die Sortierung erfolgt dabei nach Namen des Katalogs oder des Formulars. Die Sortierung erfolgt dabei nach Namen des Katalogs oder des Formulars.
Beim Modifizieren der Inhalte kann ebenfalls die Option `--sorted` dazu verwendet werden, die Einträge im Anschluss an die Modifikation
nach Namen und für Formulare der Abhängigkeit von Formularverweisen und Unterformularen zu sortieren.
Formulare, die von anderen Formularen in einem Formularverweis oder als Unterformular verwendet werden, werden dabei weiter oben angeordnet,
da Onkostar einen Formularimport sequenziell, ohne Berücksichtigung von Abhängigkeiten, durchführt.
Dies erlaubt eine konsistente Reihenfolge der Einträge, wodurch ein direkter Vergleich mit Vorversionen ermöglicht wird.
##### Entfernen von Inhalten der Systembibliothek bei Modifikation
Mit der die experimentelle Option `--strip` ist es möglich, die in der OSC-Datei enthaltenen und beim Import nicht genutzten Inhalte aus der Systembibliothek zu entfernen.
Hierbei werden alle Inhalte entfernt, die im Ordner "ONKOSTAR Bibliothek" enthalten sind, beim Import jedoch ignoriert werden.
## Profile ## Profile
Zum Erstellen von Varianten einer OSC-Datei wird eine Profildatei im YAML-Format verwendet. Zum Erstellen von Varianten einer OSC-Datei wird eine Profildatei im YAML-Format verwendet.
@@ -53,6 +128,9 @@ In ihr sind die durchzuführenden Änderungen definiert. Eine Profildatei hat di
``` ```
forms: forms:
- name: "ExampleForm" - name: "ExampleForm"
form_field:
- name: "formularfeld"
hide: true
form_references: form_references:
- name: "ref_first_mtb" - name: "ref_first_mtb"
referenced_data_form: "Formularverweis.Variante" referenced_data_form: "Formularverweis.Variante"
@@ -79,6 +157,12 @@ und dabei die vorhandenen Angaben für den Formularverweis zu ersetzen.
Die Angaben für `referenced_data_form`, `anzeige_auswahl`, `anzeige` und `scripts_code` sind optional. Die Angaben für `referenced_data_form`, `anzeige_auswahl`, `anzeige` und `scripts_code` sind optional.
Wird keine Angabe gemacht, wird der bestehende Wert beibehalten. Wird keine Angabe gemacht, wird der bestehende Wert beibehalten.
Zudem wird im Formular "ExampleForm" das Formularfeld "formularfeld" ausgeblendet, indem der Filter auf "false" gesetzt wird.
Dadurch wird das Formularfeld nie angezeigt.
Ein zuvor bestehender Filter wird ersetzt.
Weiterhin wird die Eigenschaft "Speichern" des Formularfelds auf "Immer speichern" gesetzt um sicherzustellen, dass zuvor
enthaltene Daten weiterhin gespeichert bleiben und werden, auch wenn das Formularfeld nicht sichtbar ist.
**Achtung!** Diese Anwendung überprüft keine Scripts und verwendet angegebene Scripts als "valid" im resultierenden OSC-File. **Achtung!** Diese Anwendung überprüft keine Scripts und verwendet angegebene Scripts als "valid" im resultierenden OSC-File.
Zudem kann die Menükategorie angepasst werden. Zudem kann die Menükategorie angepasst werden.
@@ -88,4 +172,4 @@ Wird sie angeben, sind die Felder `name`, `position` und `column` verpflichtend.
Es können beliebig viele Formulare mit beliebig vielen Änderungen zu Formularverweisen in einer Profildatei Es können beliebig viele Formulare mit beliebig vielen Änderungen zu Formularverweisen in einer Profildatei
hinterlegt werden, jedoch ist mindestens eine Angabe zu einem Formularfeld erforderlich. hinterlegt werden, jedoch ist mindestens eine Angabe zu einem Formularfeld erforderlich.
Beispiele für eine Profildatei sind unter [`examples/`](examples/) zu finden. Beispiele für eine Profildatei sind unter [`examples/`](/examples) zu finden.

44
build.rs Normal file
View File

@@ -0,0 +1,44 @@
/*
* MIT License
*
* Copyright (c) 2023 Comprehensive Cancer Center Mainfranken
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use std::fs;
use std::io::Error;
use clap_complete::generate_to;
use clap_complete::Shell::Bash;
include!("src/cli.rs");
fn main() -> Result<(), Error> {
let mut cmd = build_cli();
let package_name = std::env::var("CARGO_CRATE_NAME").unwrap_or("osc-variant".to_string());
fs::remove_dir_all("completion").unwrap_or_default();
fs::create_dir("completion")?;
generate_to(Bash, &mut cmd, package_name.as_str(), "completion")?;
Ok(())
}

27
examples/dnpm-master.yml Normal file
View File

@@ -0,0 +1,27 @@
forms:
- name: 'DNPM Klinik/Anamnese'
form_references:
- name: MTB
referenced_data_form: 'OS.Tumorkonferenz'
anzeige_auswahl: 'MTB vom {Datum}'
- name: 'DNPM Therapieplan'
form_references:
- name: referstemtb
referenced_data_form: 'OS.Tumorkonferenz'
anzeige_auswahl: 'MTB vom {Datum}'
- name: reftkhumangenber
referenced_data_form: 'OS.Tumorkonferenz'
anzeige_auswahl: 'MTB vom {Datum}'
- name: reftkreevaluation
referenced_data_form: 'OS.Tumorkonferenz'
anzeige_auswahl: 'MTB vom {Datum}'
- name: 'DNPM UF Einzelempfehlung'
form_references:
- name: mtb
referenced_data_form: 'OS.Tumorkonferenz'
anzeige_auswahl: 'MTB vom {Datum}'
- name: 'DNPM UF Rebiopsie'
form_references:
- name: reftumorkonferenz
referenced_data_form: 'OS.Tumorkonferenz'
anzeige_auswahl: 'MTB vom {Datum}'

View File

@@ -3,4 +3,28 @@ forms:
form_references: form_references:
- name: MTB - name: MTB
referenced_data_form: 'MR.MTB_Anmeldung' referenced_data_form: 'MR.MTB_Anmeldung'
anzeige_auswahl: 'MTB Anmeldung vom {Anmeldedatum}' anzeige_auswahl: 'MTB Anmeldung vom {Anmeldedatum}'
scripts_code: |
setFieldValue('AnmeldedatumMTB', getFieldValue('MTB').MTBTermin);
setFieldValue('WHOGrad', getFieldValue('MTB').WHOGrad);
- name: 'DNPM Therapieplan'
form_references:
- name: referstemtb
referenced_data_form: 'MR.MTB_Empfehlung'
anzeige_auswahl: 'MTB vom {Datum}'
- name: reftkhumangenber
referenced_data_form: 'MR.MTB_Empfehlung'
anzeige_auswahl: 'MTB vom {Datum}'
- name: reftkreevaluation
referenced_data_form: 'MR.MTB_Empfehlung'
anzeige_auswahl: 'MTB vom {Datum}'
- name: 'DNPM UF Einzelempfehlung'
form_references:
- name: mtb
referenced_data_form: 'MR.MTB_Empfehlung'
anzeige_auswahl: 'MTB vom {Datum}'
- name: 'DNPM UF Rebiopsie'
form_references:
- name: reftumorkonferenz
referenced_data_form: 'MR.MTB_Empfehlung'
anzeige_auswahl: 'MTB vom {Datum}'

View File

@@ -22,18 +22,28 @@
* SOFTWARE. * SOFTWARE.
*/ */
use clap::{Parser, Subcommand}; use clap::{Command, CommandFactory, Parser, Subcommand};
#[allow(dead_code)]
fn build_cli() -> Command {
Cli::command()
}
#[derive(Parser)] #[derive(Parser)]
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
#[command(propagate_version = true, arg_required_else_help(true))] #[command(propagate_version = true, arg_required_else_help(true))]
pub struct Cli { pub struct Cli {
#[command(subcommand)] #[command(subcommand)]
pub command: Command, pub cmd: SubCommand,
} }
#[derive(Subcommand)] #[derive(Subcommand)]
pub enum Command { pub enum SubCommand {
#[command(
name = "sha256sum",
about = "Berechne SHA256 Prüfsumme für die angegebene Datei"
)]
Sha256Sum { inputfile: String },
#[command(about = "Zeigt alle enthaltenen Kataloge und Formulare mit Revision an.")] #[command(about = "Zeigt alle enthaltenen Kataloge und Formulare mit Revision an.")]
List { List {
inputfile: String, inputfile: String,
@@ -42,6 +52,19 @@ pub enum Command {
help = "Sortiere Kataloge und Formulare nach Name (Optional)" help = "Sortiere Kataloge und Formulare nach Name (Optional)"
)] )]
sorted: bool, sorted: bool,
#[arg(long = "filter", help = "Filtere Ausgabe nach Name (Optional)")]
filter: Option<String>,
},
#[command(about = "Zeigt Kataloge und Formulare mit Revision und Abhängigkeiten an.")]
Tree {
inputfile: String,
#[arg(
long = "sorted",
help = "Sortiere Kataloge und Formulare nach Name (Optional)"
)]
sorted: bool,
#[arg(long = "filter", help = "Filtere Ausgabe nach Name (Optional)")]
filter: Option<String>,
}, },
#[command(about = "Modifiziert die angegebene Datei anhand der Profildatei")] #[command(about = "Modifiziert die angegebene Datei anhand der Profildatei")]
Modify { Modify {
@@ -52,5 +75,24 @@ pub enum Command {
outputfile: Option<String>, outputfile: Option<String>,
#[arg(long = "compact", help = "Kompakte Ausgabe, ohne Einrücken (Optional)")] #[arg(long = "compact", help = "Kompakte Ausgabe, ohne Einrücken (Optional)")]
compact: bool, compact: bool,
#[arg(
long = "sorted",
alias = "x-sorted",
help = "Sortiere Kataloge und Formulare nach Name (Optional)."
)]
sorted: bool,
#[arg(
long = "strip",
alias = "x-strip",
help = "Entferne Einträge aus der Systembibliothek die nicht importiert werden (Optional)."
)]
strip: bool,
},
#[command(about = "Vergleiche zwei Dateien anhand der Revision der enthaltenen Inhalte")]
Diff {
inputfile_a: String,
inputfile_b: String,
#[arg(long = "strict", help = "Strikter Vergleich des Inhalts")]
strict: bool,
}, },
} }

View File

@@ -28,13 +28,16 @@ use std::fs;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::Write; use std::io::Write;
use std::ops::Add; use std::ops::Add;
use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use clap::Parser; use clap::Parser;
use console::style;
use quick_xml::se::Serializer; use quick_xml::se::Serializer;
use serde::Serialize; use serde::Serialize;
use sha256::digest;
use crate::cli::{Cli, Command}; use crate::cli::{Cli, SubCommand};
use crate::model::onkostar_editor::OnkostarEditor; use crate::model::onkostar_editor::OnkostarEditor;
use crate::profile::Profile; use crate::profile::Profile;
@@ -108,19 +111,44 @@ fn read_profile(filename: String) -> Result<Profile, FileError> {
fn main() -> Result<(), Box<dyn Error>> { fn main() -> Result<(), Box<dyn Error>> {
let cli = Cli::parse(); let cli = Cli::parse();
match cli.command { match cli.cmd {
Command::List { inputfile, sorted } => { SubCommand::List {
inputfile,
sorted,
filter,
} => {
let mut data = read_inputfile(inputfile)?; let mut data = read_inputfile(inputfile)?;
if sorted { if sorted {
data.sorted() data.sorted()
} }
if let Some(name) = filter {
OnkostarEditor::print_list_filtered(&mut data, name.as_str());
return Ok(());
}
data.print_list(); data.print_list();
} }
Command::Modify { SubCommand::Tree {
inputfile,
sorted,
filter,
} => {
let mut data = read_inputfile(inputfile)?;
if sorted {
data.sorted()
}
if let Some(name) = filter {
OnkostarEditor::print_tree_filtered(&mut data, name.as_str());
return Ok(());
}
OnkostarEditor::print_tree(&data);
}
SubCommand::Modify {
inputfile, inputfile,
profile, profile,
outputfile, outputfile,
compact, compact,
sorted,
strip,
} => { } => {
let data = &mut read_inputfile(inputfile)?; let data = &mut read_inputfile(inputfile)?;
@@ -131,6 +159,14 @@ fn main() -> Result<(), Box<dyn Error>> {
data.apply_profile(&profile); data.apply_profile(&profile);
} }
if sorted {
data.sorted();
}
if strip {
data.strip_system_library_content();
}
let mut buf = String::new(); let mut buf = String::new();
let mut serializer = Serializer::new(&mut buf); let mut serializer = Serializer::new(&mut buf);
@@ -157,6 +193,40 @@ fn main() -> Result<(), Box<dyn Error>> {
} }
} }
} }
SubCommand::Diff {
inputfile_a,
inputfile_b,
strict,
} => {
println!(
"Vergleiche Datei A ({}) mit Datei B ({})",
style(&inputfile_a).yellow(),
style(&inputfile_b).yellow()
);
let data_a = &mut read_inputfile(inputfile_a)?;
let data_b = &mut read_inputfile(inputfile_b)?;
data_a.print_diff(data_b, strict);
}
SubCommand::Sha256Sum { inputfile } => {
match fs::read_to_string(inputfile.clone()) {
Ok(content) => {
println!(
"{} {}",
digest(content).as_str(),
PathBuf::from(inputfile.clone())
.canonicalize()
.unwrap_or_default()
.to_str()
.unwrap_or_default()
)
}
Err(err) => {
eprintln!("{}", FileError::Reading(inputfile, err.to_string()));
}
};
}
}; };
Ok(()) Ok(())

View File

@@ -22,10 +22,14 @@
* SOFTWARE. * SOFTWARE.
*/ */
use std::collections::HashSet;
use console::style; use console::style;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::model::{Listable, Ordner, Sortable}; use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires};
use crate::model::{Comparable, FolderContent, Listable, Ordner, Sortable};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
@@ -59,7 +63,11 @@ pub struct DataCatalogue {
impl Listable for DataCatalogue { impl Listable for DataCatalogue {
fn to_listed_string(&self) -> String { fn to_listed_string(&self) -> String {
format!( format!(
"Datenkatalog '{}' in Revision '{}'", "Datenkatalog ({}) '{}' in Revision '{}'",
match self.is_system_library_content() {
true => style("S").yellow(),
_ => style("u"),
},
style(&self.name).yellow(), style(&self.name).yellow(),
style(&self.revision).yellow() style(&self.revision).yellow()
) )
@@ -70,6 +78,78 @@ impl Sortable for DataCatalogue {
fn sorting_key(&self) -> String { fn sorting_key(&self) -> String {
self.name.clone() self.name.clone()
} }
fn sorted(&mut self) -> &Self {
self.entries
.entry
.sort_unstable_by_key(|item| item.sorting_key());
self.entries.entry.iter_mut().for_each(|item| {
item.sorted();
});
self
}
}
impl Comparable for DataCatalogue {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
}
impl Requires for DataCatalogue {
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement> {
let mut result = self
.entries
.entry
.iter()
.filter(|&entry| entry.property_catalogue.is_some())
.map(|entry| match &entry.property_catalogue {
Some(entry) => entry.to_string(),
_ => String::new(),
})
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| match all.find_property_catalogue(entry.as_str()) {
Some(contained) => Requirement::PropertyCatalogue(contained),
None => Requirement::ExternalPropertyCatalogue(entry),
})
.collect::<Vec<_>>();
result.sort_unstable_by_key(|item| item.sorting_key());
result
}
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String {
format!(
"{}\n{}",
self.to_listed_string(),
self.get_required_entries(all)
.iter()
.map(|entry| match entry {
Requirement::PropertyCatalogue(_) => {
Some(format!(" - {}\n", entry.to_string()))
}
Requirement::ExternalPropertyCatalogue(_) => {
Some(format!(" - {}\n", entry.to_string()))
}
_ => None,
})
.filter(Option::is_some)
.flatten()
.collect::<Vec<_>>()
.join("")
)
}
}
impl FolderContent for DataCatalogue {
fn get_library_folder(&self) -> String {
self.ordner.bibliothek.name.to_string()
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@@ -141,6 +221,23 @@ pub struct Entry {
revision: u16, revision: u16,
} }
impl Sortable for Entry {
fn sorting_key(&self) -> String {
self.name.clone()
}
fn sorted(&mut self) -> &Self
where
Self: Sized,
{
if let Some(ref mut use_) = self.use_ {
use_.program_module
.sort_unstable_by_key(|item| item.sorting_key())
}
self
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Use { pub struct Use {
@@ -156,3 +253,9 @@ pub struct ProgramModule {
#[serde(rename = "@name")] #[serde(rename = "@name")]
name: String, name: String,
} }
impl Sortable for ProgramModule {
fn sorting_key(&self) -> String {
format!("{}-{}", self.program, self.name)
}
}

View File

@@ -22,12 +22,18 @@
* SOFTWARE. * SOFTWARE.
*/ */
use std::cmp::Ordering;
use std::collections::HashSet;
use console::style; use console::style;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires};
use crate::model::{ use crate::model::{
apply_profile_to_form_entry, Ansichten, Entries, Filter, FormEntry, FormEntryContainer, apply_profile_to_form_entry, apply_profile_to_form_field, Ansichten, Comparable, Entries,
Listable, MenuCategory, PlausibilityRules, Script, Sortable, Filter, FolderContent, FormEntry, FormEntryContainer, Listable, MenuCategory,
PlausibilityRules, RefEntries, Script, Sortable,
}; };
use crate::model::{Haeufigkeiten, Ordner}; use crate::model::{Haeufigkeiten, Ordner};
use crate::profile::Profile; use crate::profile::Profile;
@@ -165,6 +171,12 @@ impl FormEntryContainer for DataForm {
apply_profile_to_form_entry(entry, form_reference) apply_profile_to_form_entry(entry, form_reference)
}); });
// Hide form field using filter set to "false" if requested
profile_form
.form_fields
.iter()
.for_each(|form_field| apply_profile_to_form_field(entry, form_field));
if let Some(menu_category) = &profile_form.menu_category { if let Some(menu_category) = &profile_form.menu_category {
self.menu_category = Some(MenuCategory { self.menu_category = Some(MenuCategory {
name: menu_category.name.clone(), name: menu_category.name.clone(),
@@ -181,9 +193,25 @@ impl FormEntryContainer for DataForm {
impl Listable for DataForm { impl Listable for DataForm {
fn to_listed_string(&self) -> String { fn to_listed_string(&self) -> String {
format!( format!(
"Formular '{}' in Revision '{}'", "Formular ({}) '{}' in Revision '{}' {}",
match self.is_system_library_content() {
true => style("S").yellow(),
_ => style("u"),
},
style(&self.name).yellow(), style(&self.name).yellow(),
style(&self.revision).yellow() style(&self.revision).yellow(),
if self
.entries
.entry
.iter()
.filter(|entry| entry.procedure_date_status != "none")
.count()
== 0
{
style("Formular hat keine Angabe zum Prozedurdatum!").red()
} else {
style("")
}
) )
} }
} }
@@ -192,6 +220,153 @@ impl Sortable for DataForm {
fn sorting_key(&self) -> String { fn sorting_key(&self) -> String {
self.name.clone() self.name.clone()
} }
fn sorted(&mut self) -> &Self {
self.data_catalogues.data_catalogue.sort_unstable();
self.entries
.entry
.sort_unstable_by_key(|item| item.sorting_key());
self.entries.entry.iter_mut().for_each(|item| {
item.sorted();
});
if let Some(ref mut plausibility_rule) = self.plausibility_rules.plausibility_rule {
plausibility_rule.sort_unstable_by_key(|item| item.bezeichnung.clone());
plausibility_rule.iter_mut().for_each(|item| {
if let Some(ref mut data_form_entry_names) = item.data_form_entries.entry_name {
data_form_entry_names.sort_unstable();
}
});
}
self
}
}
impl Comparable for DataForm {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
fn compare_by_requirement(a: &Self, b: &Self) -> Ordering {
if a.get_name() == b.get_name()
|| a.is_system_library_content()
|| b.is_system_library_content()
{
return Ordering::Equal;
}
if a.requires_form_reference(&b.get_name()) || a.requires_subform(&b.get_name()) {
return Ordering::Greater;
}
Ordering::Less
}
}
impl Requires for DataForm {
fn requires_form_reference(&self, name: &str) -> bool {
self.entries
.entry
.iter()
.map(|item| {
item.type_ == "formReference"
&& match item.referenced_data_form.as_ref() {
Some(refname) => refname == name,
_ => false,
}
})
.filter(|&it| it)
.last()
.unwrap_or_default()
}
fn requires_subform(&self, name: &str) -> bool {
self.entries
.entry
.iter()
.map(|item| {
item.type_ == "subform"
&& match item.referenced_data_form.as_ref() {
Some(refname) => refname == name,
_ => false,
}
})
.filter(|&it| it)
.last()
.unwrap_or_default()
}
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement> {
let mut result = self
.data_catalogues
.data_catalogue
.iter()
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| match all.find_data_catalogue(entry.as_str()) {
Some(contained) => Requirement::DataCatalogue(contained),
None => Requirement::ExternalDataCatalogue(entry.to_string()),
})
.collect::<Vec<_>>();
result.sort_unstable_by_key(|item| item.sorting_key());
let referenced_forms = &mut self
.entries
.entry
.iter()
.filter(|&entry| entry.get_type() == "formReference")
.filter_map(|entry| match &entry.referenced_data_form {
Some(name) => Some(name),
None => None,
})
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| match all.find_data_form(entry.as_str()) {
Some(contained) => Requirement::DataFormReference(contained),
None => match all.find_unterformular(entry.as_str()) {
Some(contained) => Requirement::UnterformularReference(contained),
None => Requirement::ExternalUnterformularReference(entry.to_string()),
},
})
.collect::<Vec<_>>();
referenced_forms.sort_unstable_by_key(|item| item.sorting_key());
result.append(referenced_forms);
let sub_forms = &mut self
.entries
.entry
.iter()
.filter(|&entry| entry.get_type() == "subform")
.filter_map(|entry| match &entry.referenced_data_form {
Some(name) => Some(name),
None => None,
})
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| match all.find_data_form(entry.as_str()) {
Some(contained) => Requirement::DataFormSubform(contained),
None => match all.find_unterformular(entry.as_str()) {
Some(contained) => Requirement::UnterformularSubform(contained),
None => Requirement::ExternalUnterformularSubform(entry.to_string()),
},
})
.collect::<Vec<_>>();
sub_forms.sort_unstable_by_key(|item| item.sorting_key());
result.append(sub_forms);
result
}
}
impl FolderContent for DataForm {
fn get_library_folder(&self) -> String {
self.ordner.bibliothek.name.to_string()
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@@ -375,6 +550,9 @@ pub struct Entry {
direction_pat_modul: String, direction_pat_modul: String,
#[serde(rename = "SeitenumbruchPatModul")] #[serde(rename = "SeitenumbruchPatModul")]
seitenumbruch_pat_modul: bool, seitenumbruch_pat_modul: bool,
#[serde(rename = "Kontaktliste")]
#[serde(skip_serializing_if = "Option::is_none")]
kontaktliste: Option<String>,
#[serde(rename = "MarkierungIgnorieren")] #[serde(rename = "MarkierungIgnorieren")]
markierung_ignorieren: bool, markierung_ignorieren: bool,
#[serde(rename = "SucheArt")] #[serde(rename = "SucheArt")]
@@ -421,6 +599,35 @@ impl FormEntry for Entry {
valid: true, valid: true,
}); });
} }
fn hide(&mut self) {
self.filter = Some(Filter {
condition: "false".into(),
valid: true,
ref_entries: Some(RefEntries { ref_entry: None }),
});
self.speichern = "0".into()
}
}
impl Sortable for Entry {
fn sorting_key(&self) -> String {
self.name.clone()
}
fn sorted(&mut self) -> &Self
where
Self: Sized,
{
if let Some(ref mut filter) = self.filter {
if let Some(ref mut ref_entries) = filter.ref_entries {
if let Some(ref mut ref_entry) = ref_entries.ref_entry {
ref_entry.sort_unstable()
}
}
}
self
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]

View File

@@ -22,13 +22,21 @@
* SOFTWARE. * SOFTWARE.
*/ */
use crate::profile::{FormReference, Profile}; use std::cmp::Ordering;
use std::collections::hash_map::DefaultHasher;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use crate::model::requirements::Requires;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::profile::{FormField, FormReference, Profile};
pub mod data_catalogue; pub mod data_catalogue;
pub mod data_form; pub mod data_form;
pub mod onkostar_editor; pub mod onkostar_editor;
pub mod property_catalogue; pub mod property_catalogue;
pub mod requirements;
pub mod unterformular; pub mod unterformular;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@@ -226,6 +234,15 @@ where
} }
} }
fn apply_profile_to_form_field<E>(entry: &mut E, form_field: &FormField)
where
E: FormEntry,
{
if entry.get_name() == form_field.name && form_field.hide {
entry.hide()
}
}
pub trait FormEntryContainer { pub trait FormEntryContainer {
fn apply_profile(&mut self, profile: &Profile); fn apply_profile(&mut self, profile: &Profile);
} }
@@ -236,6 +253,29 @@ pub trait Listable {
pub trait Sortable { pub trait Sortable {
fn sorting_key(&self) -> String; fn sorting_key(&self) -> String;
fn sorted(&mut self) -> &Self
where
Self: Sized,
{
self
}
}
pub trait Comparable: Debug {
fn get_name(&self) -> String;
fn get_revision(&self) -> u16;
fn get_hash(&self) -> String {
let mut h = DefaultHasher::new();
format!("{:?}", self).hash(&mut h);
h.finish().to_string()
}
fn compare_by_requirement(_: &Self, _: &Self) -> Ordering
where
Self: Requires,
{
Ordering::Equal
}
} }
pub trait FormEntry { pub trait FormEntry {
@@ -245,4 +285,13 @@ pub trait FormEntry {
fn update_anzeige(&mut self, value: String); fn update_anzeige(&mut self, value: String);
fn update_anzeige_auswahl(&mut self, value: String); fn update_anzeige_auswahl(&mut self, value: String);
fn update_scripts_code(&mut self, value: String); fn update_scripts_code(&mut self, value: String);
fn hide(&mut self);
}
pub trait FolderContent {
fn get_library_folder(&self) -> String;
fn is_system_library_content(&self) -> bool {
"ONKOSTAR Bibliothek" == self.get_library_folder()
}
} }

View File

@@ -1,7 +1,7 @@
/* /*
* MIT License * MIT License
* *
* 2023 Comprehensive Cancer Center Mainfranken * Copyright (c) 2023 Comprehensive Cancer Center Mainfranken
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy * Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal * of this software and associated documentation files (the "Software"), to deal
@@ -22,16 +22,20 @@
* SOFTWARE. * SOFTWARE.
*/ */
use std::cmp::Ordering;
use std::fmt::Debug;
use std::str::FromStr;
use console::style; use console::style;
use quick_xml::de::from_str; use quick_xml::de::from_str;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::str::FromStr;
use crate::model::data_catalogue::DataCatalogue; use crate::model::data_catalogue::DataCatalogue;
use crate::model::data_form::DataForm; use crate::model::data_form::DataForm;
use crate::model::property_catalogue::PropertyCatalogue; use crate::model::property_catalogue::PropertyCatalogue;
use crate::model::requirements::Requires;
use crate::model::unterformular::Unterformular; use crate::model::unterformular::Unterformular;
use crate::model::{FormEntryContainer, Listable, Sortable}; use crate::model::{Comparable, FolderContent, FormEntryContainer, Listable, Sortable};
use crate::profile::Profile; use crate::profile::Profile;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@@ -44,13 +48,73 @@ pub struct OnkostarEditor {
} }
impl OnkostarEditor { impl OnkostarEditor {
pub fn find_property_catalogue<'a>(&'a self, name: &str) -> Option<&'a PropertyCatalogue> {
match self
.editor
.property_catalogue
.iter()
.filter(|&item| item.get_name().eq_ignore_ascii_case(name))
.nth(0)
{
Some(x) => Some(x),
_ => None,
}
}
pub fn find_data_catalogue<'a>(&'a self, name: &str) -> Option<&'a DataCatalogue> {
match self
.editor
.data_catalogue
.iter()
.filter(|&item| item.get_name().eq_ignore_ascii_case(name))
.nth(0)
{
Some(x) => Some(x),
_ => None,
}
}
pub fn find_data_form<'a>(&'a self, name: &str) -> Option<&'a DataForm> {
match self
.editor
.data_form
.iter()
.filter(|&item| item.get_name().eq_ignore_ascii_case(name))
.nth(0)
{
Some(x) => Some(x),
_ => None,
}
}
pub fn find_unterformular<'a>(&'a self, name: &str) -> Option<&'a Unterformular> {
match self
.editor
.unterformular
.iter()
.filter(|&item| item.get_name().eq_ignore_ascii_case(name))
.nth(0)
{
Some(x) => Some(x),
_ => None,
}
}
pub fn apply_profile(&mut self, profile: &Profile) { pub fn apply_profile(&mut self, profile: &Profile) {
self.editor.data_form.iter_mut().for_each(|data_form| { self.editor
data_form.apply_profile(profile); .data_form
}); .iter_mut()
self.editor.unterformular.iter_mut().for_each(|data_form| { .filter(|data_form| !data_form.is_system_library_content())
data_form.apply_profile(profile); .for_each(|data_form| {
}) data_form.apply_profile(profile);
});
self.editor
.unterformular
.iter_mut()
.filter(|data_form| !data_form.is_system_library_content())
.for_each(|data_form| {
data_form.apply_profile(profile);
});
} }
pub fn print_list(&self) { pub fn print_list(&self) {
@@ -66,28 +130,271 @@ impl OnkostarEditor {
Self::print_items("Unterformulare", &self.editor.unterformular); Self::print_items("Unterformulare", &self.editor.unterformular);
} }
fn filter_by_name_contains(&mut self, name: &str) {
self.editor
.property_catalogue
.retain(|e| e.get_name().contains(name));
self.editor
.data_catalogue
.retain(|e| e.get_name().contains(name));
self.editor
.data_form
.retain(|e| e.get_name().contains(name));
self.editor
.unterformular
.retain(|e| e.get_name().contains(name));
}
pub fn print_list_filtered(&mut self, name: &str) {
println!(
"Die Datei wurde am {} mit {} in Version {} erstellt.\n\nFolgende Inhalte für '{}' sind gespeichert",
style(&self.info_xml.datum_xml).yellow(),
style(&self.info_xml.name).yellow(),
style(&self.info_xml.version).yellow(),
name
);
self.filter_by_name_contains(name);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue);
Self::print_items("Datenkataloge", &self.editor.data_catalogue);
Self::print_items("Formulare", &self.editor.data_form);
Self::print_items("Unterformulare", &self.editor.unterformular);
}
fn print_items(title: &str, list: &[impl Listable]) { fn print_items(title: &str, list: &[impl Listable]) {
println!("\n{} {}", list.len(), style(title).underlined()); print!("\n{} {}", list.len(), style(title).underlined());
println!(
" - Inhalte der Systembibliothek sind mit ({}), der Benutzerbibliothek mit (u) markiert",
style("S").yellow()
);
list.iter() list.iter()
.for_each(|entry| println!("{}", entry.to_listed_string())); .for_each(|entry| println!("{}", entry.to_listed_string()));
} }
pub fn print_tree(&self) {
println!(
"Die Datei wurde am {} mit {} in Version {} erstellt.\n\nFolgende Inhalte sind gespeichert",
style(&self.info_xml.datum_xml).yellow(),
style(&self.info_xml.name).yellow(),
style(&self.info_xml.version).yellow()
);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue);
self.print_items_tree("Datenkataloge", &self.editor.data_catalogue);
self.print_items_tree("Formulare", &self.editor.data_form);
self.print_items_tree("Unterformulare", &self.editor.unterformular);
}
pub fn print_tree_filtered(&mut self, name: &str) {
println!(
"Die Datei wurde am {} mit {} in Version {} erstellt.\n\nFolgende Inhalte für '{}' sind gespeichert",
style(&self.info_xml.datum_xml).yellow(),
style(&self.info_xml.name).yellow(),
style(&self.info_xml.version).yellow(),
name
);
self.filter_by_name_contains(name);
Self::print_items("Merkmalskataloge", &self.editor.property_catalogue);
self.print_items_tree("Datenkataloge", &self.editor.data_catalogue);
self.print_items_tree("Formulare", &self.editor.data_form);
self.print_items_tree("Unterformulare", &self.editor.unterformular);
}
fn print_items_tree(&self, title: &str, list: &[impl Requires]) {
print!("\n{} {}", list.len(), style(title).underlined());
println!(
" - Inhalte der Systembibliothek sind mit ({}), der Benutzerbibliothek mit (u) markiert",
style("S").yellow()
);
list.iter()
.for_each(|entry| println!("{}", entry.to_requirement_string(self)));
}
pub fn sorted(&mut self) { pub fn sorted(&mut self) {
self.editor self.editor
.property_catalogue .property_catalogue
.sort_unstable_by_key(|e| e.sorting_key()); .sort_unstable_by_key(|e| e.sorting_key());
self.editor.property_catalogue.iter_mut().for_each(|item| {
item.sorted();
});
self.editor self.editor
.data_catalogue .data_catalogue
.sort_unstable_by_key(|e| e.sorting_key()); .sort_unstable_by_key(|e| e.sorting_key());
self.editor.data_catalogue.iter_mut().for_each(|item| {
item.sorted();
});
/*self.editor
.data_form
.sort_unstable_by_key(|e| e.sorting_key());*/
self.editor self.editor
.data_form .data_form
.sort_unstable_by_key(|e| e.sorting_key()); .sort_unstable_by(DataForm::compare_by_requirement);
self.editor.data_form.iter_mut().for_each(|item| {
item.sorted();
});
/*self.editor
.unterformular
.sort_unstable_by_key(|e| e.sorting_key());*/
self.editor self.editor
.unterformular .unterformular
.sort_unstable_by_key(|e| e.sorting_key()); .sort_unstable_by(Unterformular::compare_by_requirement);
self.editor.unterformular.iter_mut().for_each(|item| {
item.sorted();
});
}
pub fn strip_system_library_content(&mut self) {
self.editor
.property_catalogue
.retain(|e| !e.is_system_library_content());
self.editor
.data_catalogue
.retain(|e| !e.is_system_library_content());
self.editor
.data_form
.retain(|e| !e.is_system_library_content());
self.editor
.unterformular
.retain(|e| !e.is_system_library_content());
}
pub fn print_diff(&mut self, other: &mut Self, strict: bool) {
println!();
println!(
"Datei A wurde am {} mit {} in Version {} erstellt.",
style(&self.info_xml.datum_xml).yellow(),
style(&self.info_xml.name).yellow(),
style(&self.info_xml.version).yellow()
);
println!(
"Datei B wurde am {} mit {} in Version {} erstellt.",
style(&other.info_xml.datum_xml).yellow(),
style(&other.info_xml.name).yellow(),
style(&other.info_xml.version).yellow()
);
self.sorted();
other.sorted();
Self::print_item_diff(
"Merkmalskataloge",
&self.editor.property_catalogue,
&other.editor.property_catalogue,
strict,
);
Self::print_item_diff(
"Datenkataloge",
&self.editor.data_catalogue,
&other.editor.data_catalogue,
strict,
);
Self::print_item_diff(
"Formulare",
&self.editor.data_form,
&other.editor.data_form,
strict,
);
Self::print_item_diff(
"Unterformulare",
&self.editor.unterformular,
&other.editor.unterformular,
strict,
);
}
fn print_item_diff(
title: &str,
list_a: &[impl Comparable],
list_b: &[impl Comparable],
strict: bool,
) {
println!("\n{}", style(title).underlined());
let mut has_diff = false;
let names_a = list_a
.iter()
.map(|entry| entry.get_name())
.collect::<Vec<_>>();
let names_b = list_b
.iter()
.map(|entry| entry.get_name())
.collect::<Vec<_>>();
names_b.iter().for_each(|entry| {
if !names_a.contains(entry) {
println!("{}: {}", entry, style("Nicht in Datei A enthalten!").red());
has_diff = true;
}
});
names_a.iter().for_each(|entry| {
if !names_b.contains(entry) {
println!("{}: {}", entry, style("Nicht in Datei B enthalten!").red());
has_diff = true;
}
});
list_a.iter().for_each(|entry_a| {
list_b.iter().for_each(|entry_b| {
if entry_a.get_name() == entry_b.get_name() {
match entry_a.get_revision().cmp(&entry_b.get_revision()) {
Ordering::Less => {
println!(
"{}: {} (Revision {} < Revision {})",
entry_a.get_name(),
style("Neuer in Datei B").yellow(),
style(entry_a.get_revision()).blue(),
style(entry_b.get_revision()).green()
);
has_diff = true;
}
Ordering::Greater => {
println!(
"{}: {} (Revision {} > Revision {})",
entry_a.get_name(),
style("Neuer in Datei A").yellow(),
style(entry_a.get_revision()).green(),
style(entry_b.get_revision()).blue()
);
has_diff = true;
}
_ => {
if strict && entry_a.get_hash() != entry_b.get_hash() {
println!(
"{}: {} (z.B. GUID oder Reihenfolge von Unterelementen)",
entry_a.get_name(),
style("Inhaltlich verschieden").yellow()
);
has_diff = true;
} else if strict {
println!("{}: {}", entry_a.get_name(), style("Identisch").green())
}
}
}
}
});
});
if !has_diff {
println!("Keine Unterschiede")
}
} }
} }
@@ -116,12 +423,12 @@ pub struct InfoXML {
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
struct Editor { struct Editor {
#[serde(rename = "PropertyCatalogue")] #[serde(rename = "PropertyCatalogue", default)]
property_catalogue: Vec<PropertyCatalogue>, property_catalogue: Vec<PropertyCatalogue>,
#[serde(rename = "DataCatalogue")] #[serde(rename = "DataCatalogue", default)]
data_catalogue: Vec<DataCatalogue>, data_catalogue: Vec<DataCatalogue>,
#[serde(rename = "Unterformular")] #[serde(rename = "Unterformular", default)]
unterformular: Vec<Unterformular>, unterformular: Vec<Unterformular>,
#[serde(rename = "DataForm")] #[serde(rename = "DataForm", default)]
data_form: Vec<DataForm>, data_form: Vec<DataForm>,
} }

View File

@@ -25,7 +25,7 @@
use console::style; use console::style;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::model::{Listable, Ordner, Sortable}; use crate::model::{Comparable, FolderContent, Listable, Ordner, Sortable};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
@@ -56,7 +56,11 @@ pub struct PropertyCatalogue {
impl Listable for PropertyCatalogue { impl Listable for PropertyCatalogue {
fn to_listed_string(&self) -> String { fn to_listed_string(&self) -> String {
format!( format!(
"Merkmalskatalog '{}' in Revision '{}'", "Merkmalskatalog ({}) '{}' in Revision '{}'",
match self.is_system_library_content() {
true => style("S").yellow(),
_ => style("u"),
},
style(&self.name).yellow(), style(&self.name).yellow(),
style(&self.revision).yellow() style(&self.revision).yellow()
) )
@@ -67,6 +71,32 @@ impl Sortable for PropertyCatalogue {
fn sorting_key(&self) -> String { fn sorting_key(&self) -> String {
self.name.clone() self.name.clone()
} }
fn sorted(&mut self) -> &Self {
if let Some(ref mut versions) = self.versions.entry {
versions.sort_unstable_by_key(|item| item.version_number);
versions.iter_mut().for_each(|version| {
version.sorted();
});
}
self
}
}
impl Comparable for PropertyCatalogue {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
}
impl FolderContent for PropertyCatalogue {
fn get_library_folder(&self) -> String {
self.ordner.bibliothek.name.to_string()
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@@ -105,6 +135,40 @@ pub struct Version {
categories: Categories, categories: Categories,
} }
impl Sortable for Version {
fn sorting_key(&self) -> String {
self.oid.clone()
}
fn sorted(&mut self) -> &Self
where
Self: Sized,
{
if let Some(ref mut abbildung) = self.abbildung {
abbildung.sort_unstable_by_key(|item| item.sorting_key());
abbildung.iter_mut().for_each(|item| {
item.sorted();
});
}
self.entries
.content
.sort_unstable_by_key(|item| item.sorting_key());
self.entries.content.iter_mut().for_each(|item| {
item.sorted();
});
self.categories
.content
.sort_unstable_by_key(|item| item.sorting_key());
self.categories.content.iter_mut().for_each(|item| {
item.sorted();
});
self
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct VersionEntries { pub struct VersionEntries {
@@ -131,6 +195,12 @@ pub struct VersionEntry {
position: String, position: String,
} }
impl Sortable for VersionEntry {
fn sorting_key(&self) -> String {
self.code.clone()
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Categories { pub struct Categories {
@@ -155,6 +225,26 @@ pub struct Category {
category_entries: CategoryEntries, category_entries: CategoryEntries,
} }
impl Sortable for Category {
fn sorting_key(&self) -> String {
self.name.clone()
}
fn sorted(&mut self) -> &Self
where
Self: Sized,
{
self.category_entries
.content
.sort_unstable_by_key(|item| item.sorting_key());
self.category_entries.content.iter_mut().for_each(|item| {
item.sorted();
});
self
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct CategoryEntries { pub struct CategoryEntries {
@@ -181,6 +271,12 @@ pub struct CategoryEntry {
note: Option<String>, note: Option<String>,
} }
impl Sortable for CategoryEntry {
fn sorting_key(&self) -> String {
self.code.clone()
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct Abbildung { pub struct Abbildung {
@@ -190,6 +286,24 @@ pub struct Abbildung {
content: Vec<AbbildungEintrag>, content: Vec<AbbildungEintrag>,
} }
impl Sortable for Abbildung {
fn sorting_key(&self) -> String {
self.ziel_mk_version_oid.clone()
}
fn sorted(&mut self) -> &Self
where
Self: Sized,
{
self.content.sort_unstable_by_key(|item| item.sorting_key());
self.content.iter_mut().for_each(|item| {
item.sorted();
});
self
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct AbbildungEintrag { pub struct AbbildungEintrag {
@@ -199,6 +313,12 @@ pub struct AbbildungEintrag {
entry_to: AbbildungEntry, entry_to: AbbildungEntry,
} }
impl Sortable for AbbildungEintrag {
fn sorting_key(&self) -> String {
format!("{}-{}", self.entry_from.code, self.entry_to.code)
}
}
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct AbbildungEntry { pub struct AbbildungEntry {

163
src/model/requirements.rs Normal file
View File

@@ -0,0 +1,163 @@
/*
* MIT License
*
* Copyright (c) 2023 Comprehensive Cancer Center Mainfranken
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
use crate::model::data_catalogue::DataCatalogue;
use crate::model::data_form::DataForm;
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::property_catalogue::PropertyCatalogue;
use crate::model::unterformular::Unterformular;
use crate::model::{Comparable, Listable, Sortable};
#[allow(clippy::enum_variant_names)]
pub enum Requirement<'a> {
PropertyCatalogue(&'a PropertyCatalogue),
DataCatalogue(&'a DataCatalogue),
ExternalPropertyCatalogue(String),
ExternalDataCatalogue(String),
DataFormReference(&'a DataForm),
UnterformularReference(&'a Unterformular),
#[allow(dead_code)]
ExternalDataFormReference(String),
ExternalUnterformularReference(String),
DataFormSubform(&'a DataForm),
UnterformularSubform(&'a Unterformular),
#[allow(dead_code)]
ExternalDataFormSubform(String),
ExternalUnterformularSubform(String),
}
impl Sortable for Requirement<'_> {
fn sorting_key(&self) -> String {
match self {
Requirement::PropertyCatalogue(item) => item.get_name(),
Requirement::DataCatalogue(item) => item.get_name(),
Requirement::DataFormReference(item) => item.get_name(),
Requirement::UnterformularReference(item) => item.get_name(),
Requirement::DataFormSubform(item) => item.get_name(),
Requirement::UnterformularSubform(item) => item.get_name(),
Requirement::ExternalPropertyCatalogue(name)
| Requirement::ExternalDataCatalogue(name)
| Requirement::ExternalDataFormReference(name)
| Requirement::ExternalDataFormSubform(name)
| Requirement::ExternalUnterformularReference(name)
| Requirement::ExternalUnterformularSubform(name) => name.to_string(),
}
}
}
impl ToString for Requirement<'_> {
fn to_string(&self) -> String {
match self {
Requirement::PropertyCatalogue(item) => item.to_listed_string(),
Requirement::DataCatalogue(item) => item.to_listed_string(),
Requirement::DataFormReference(item) => item.to_listed_string(),
Requirement::UnterformularReference(item) => item.to_listed_string(),
Requirement::DataFormSubform(item) => item.to_listed_string(),
Requirement::UnterformularSubform(item) => item.to_listed_string(),
Requirement::ExternalPropertyCatalogue(name) => {
format!("Merkmalskatalog (-) '{}' - hier nicht enthalten", name)
}
Requirement::ExternalDataCatalogue(name) => {
format!("Datenkatalog (-) '{}' - hier nicht enthalten", name)
}
Requirement::ExternalDataFormReference(name)
| Requirement::ExternalDataFormSubform(name) => {
format!("Formular (-) '{}' - hier nicht enthalten", name)
}
Requirement::ExternalUnterformularReference(name)
| Requirement::ExternalUnterformularSubform(name) => {
format!("Unterformular (-) '{}' - hier nicht enthalten", name)
}
}
}
}
pub trait Requires
where
Self: Listable,
{
fn requires_form_reference(&self, _: &str) -> bool {
false
}
fn requires_subform(&self, _: &str) -> bool {
false
}
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement>;
fn to_requirement_string<'a>(&'a self, all: &'a OnkostarEditor) -> String {
format!(
"{}\n{}",
self.to_listed_string(),
self.get_required_entries(all)
.iter()
.map(|entry| match entry {
Requirement::DataCatalogue(x) => {
let inner = x
.get_required_entries(all)
.iter()
.map(|inner_entry| match inner_entry {
Requirement::PropertyCatalogue(_) => Some(inner_entry.to_string()),
Requirement::ExternalPropertyCatalogue(_) => {
Some(inner_entry.to_string())
}
_ => None,
})
.filter(Option::is_some)
.map(|item| format!(" - {}\n", item.unwrap()))
.collect::<Vec<_>>()
.join("");
if inner.is_empty() {
Some(format!(" + {}\n", x.to_listed_string()))
} else {
Some(format!(" + {}\n{}", x.to_listed_string(), inner))
}
}
Requirement::ExternalDataCatalogue(_) => {
Some(format!(" + {}\n", entry.to_string()))
}
Requirement::DataFormReference(_)
| Requirement::ExternalDataFormReference(_)
| Requirement::UnterformularReference(_)
| Requirement::ExternalUnterformularReference(_) => {
Some(format!(" > {}\n", entry.to_string()))
}
Requirement::DataFormSubform(_)
| Requirement::ExternalDataFormSubform(_)
| Requirement::UnterformularSubform(_)
| Requirement::ExternalUnterformularSubform(_) => {
Some(format!(" * {}\n", entry.to_string()))
}
_ => None,
})
.filter(Option::is_some)
.flatten()
.collect::<Vec<_>>()
.join("")
)
}
}

View File

@@ -22,12 +22,18 @@
* SOFTWARE. * SOFTWARE.
*/ */
use std::cmp::Ordering;
use std::collections::HashSet;
use console::style; use console::style;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::model::onkostar_editor::OnkostarEditor;
use crate::model::requirements::{Requirement, Requires};
use crate::model::{ use crate::model::{
apply_profile_to_form_entry, Ansichten, Entries, Filter, FormEntry, FormEntryContainer, apply_profile_to_form_entry, apply_profile_to_form_field, Ansichten, Comparable, Entries,
Listable, MenuCategory, PlausibilityRules, Script, Sortable, Filter, FolderContent, FormEntry, FormEntryContainer, Listable, MenuCategory,
PlausibilityRules, RefEntries, Script, Sortable,
}; };
use crate::model::{Haeufigkeiten, Ordner}; use crate::model::{Haeufigkeiten, Ordner};
use crate::profile::Profile; use crate::profile::Profile;
@@ -176,6 +182,12 @@ impl FormEntryContainer for Unterformular {
apply_profile_to_form_entry(entry, form_reference) apply_profile_to_form_entry(entry, form_reference)
}); });
// Hide form field using filter set to "false" if requested
profile_form
.form_fields
.iter()
.for_each(|form_field| apply_profile_to_form_field(entry, form_field));
if let Some(menu_category) = &profile_form.menu_category { if let Some(menu_category) = &profile_form.menu_category {
self.menu_category = Some(MenuCategory { self.menu_category = Some(MenuCategory {
name: menu_category.name.clone(), name: menu_category.name.clone(),
@@ -191,18 +203,19 @@ impl FormEntryContainer for Unterformular {
impl Listable for Unterformular { impl Listable for Unterformular {
fn to_listed_string(&self) -> String { fn to_listed_string(&self) -> String {
if self.hat_unterformulare {
return format!(
"Unterformular '{}' in Revision '{}' {}",
style(&self.name).yellow(),
style(&self.revision).yellow(),
style("Unterformular mit Markierung 'hat Unterformulare'!").red()
);
}
format!( format!(
"Unterformular '{}' in Revision '{}'", "Unterformular ({}) '{}' in Revision '{}' {}",
match self.is_system_library_content() {
true => style("S").yellow(),
_ => style("u"),
},
style(&self.name).yellow(), style(&self.name).yellow(),
style(&self.revision).yellow() style(&self.revision).yellow(),
if self.hat_unterformulare {
style("Unterformular mit Markierung 'hat Unterformulare'!").red()
} else {
style("")
}
) )
} }
} }
@@ -211,6 +224,154 @@ impl Sortable for Unterformular {
fn sorting_key(&self) -> String { fn sorting_key(&self) -> String {
self.name.clone() self.name.clone()
} }
fn sorted(&mut self) -> &Self {
self.data_catalogues.data_catalogue.sort_unstable();
self.entries
.entry
.sort_unstable_by_key(|item| item.sorting_key());
self.entries.entry.iter_mut().for_each(|item| {
item.sorted();
});
if let Some(ref mut plausibility_rule) = self.plausibility_rules.plausibility_rule {
plausibility_rule.sort_unstable_by_key(|item| item.bezeichnung.clone());
plausibility_rule.iter_mut().for_each(|item| {
if let Some(ref mut data_form_entry_names) = item.data_form_entries.entry_name {
data_form_entry_names.sort_unstable();
}
});
}
self
}
}
impl Comparable for Unterformular {
fn get_name(&self) -> String {
self.name.clone()
}
fn get_revision(&self) -> u16 {
self.revision
}
fn compare_by_requirement(a: &Self, b: &Self) -> Ordering {
if a.get_name() == b.get_name()
|| a.is_system_library_content()
|| b.is_system_library_content()
{
return Ordering::Equal;
}
if a.requires_form_reference(&b.get_name()) || a.requires_subform(&b.get_name()) {
return Ordering::Greater;
}
Ordering::Less
}
}
impl Requires for Unterformular {
fn requires_form_reference(&self, name: &str) -> bool {
self.entries
.entry
.iter()
.map(|item| {
item.type_ == "formReference"
&& match item.referenced_data_form.as_ref() {
Some(refname) => refname == name,
_ => false,
}
})
.filter(|&it| it)
.last()
.unwrap_or_default()
}
fn requires_subform(&self, name: &str) -> bool {
self.entries
.entry
.iter()
.map(|item| {
item.type_ == "subform"
&& match item.referenced_data_form.as_ref() {
Some(refname) => refname == name,
_ => false,
}
})
.filter(|&it| it)
.last()
.unwrap_or_default()
}
fn get_required_entries<'a>(&'a self, all: &'a OnkostarEditor) -> Vec<Requirement> {
let mut result = self
.data_catalogues
.data_catalogue
.iter()
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| match all.find_data_catalogue(entry.as_str()) {
Some(contained) => Requirement::DataCatalogue(contained),
None => Requirement::ExternalDataCatalogue(entry.to_string()),
})
.collect::<Vec<_>>();
result.sort_unstable_by_key(|item| item.sorting_key());
let referenced_forms = &mut self
.entries
.entry
.iter()
.filter(|&entry| entry.get_type() == "formReference")
.filter_map(|entry| match &entry.referenced_data_form {
Some(name) => Some(name),
None => None,
})
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| match all.find_data_form(entry.as_str()) {
Some(contained) => Requirement::DataFormReference(contained),
None => match all.find_unterformular(entry.as_str()) {
Some(contained) => Requirement::UnterformularReference(contained),
None => Requirement::ExternalUnterformularReference(entry.to_string()),
},
})
.collect::<Vec<_>>();
referenced_forms.sort_unstable_by_key(|item| item.sorting_key());
result.append(referenced_forms);
let sub_forms = &mut self
.entries
.entry
.iter()
.filter(|&entry| entry.get_type() == "subform")
.filter_map(|entry| match &entry.referenced_data_form {
Some(name) => Some(name),
None => None,
})
.collect::<HashSet<_>>()
.into_iter()
.map(|entry| match all.find_data_form(entry.as_str()) {
Some(contained) => Requirement::DataFormSubform(contained),
None => match all.find_unterformular(entry.as_str()) {
Some(contained) => Requirement::UnterformularSubform(contained),
None => Requirement::ExternalUnterformularSubform(entry.to_string()),
},
})
.collect::<Vec<_>>();
sub_forms.sort_unstable_by_key(|item| item.sorting_key());
result.append(sub_forms);
result
}
}
impl FolderContent for Unterformular {
fn get_library_folder(&self) -> String {
self.ordner.bibliothek.name.to_string()
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
@@ -395,6 +556,9 @@ pub struct Entry {
direction_pat_modul: String, direction_pat_modul: String,
#[serde(rename = "SeitenumbruchPatModul")] #[serde(rename = "SeitenumbruchPatModul")]
seitenumbruch_pat_modul: bool, seitenumbruch_pat_modul: bool,
#[serde(rename = "Kontaktliste")]
#[serde(skip_serializing_if = "Option::is_none")]
kontaktliste: Option<String>,
#[serde(rename = "MarkierungIgnorieren")] #[serde(rename = "MarkierungIgnorieren")]
markierung_ignorieren: bool, markierung_ignorieren: bool,
#[serde(rename = "SucheArt")] #[serde(rename = "SucheArt")]
@@ -441,6 +605,35 @@ impl FormEntry for Entry {
valid: true, valid: true,
}); });
} }
fn hide(&mut self) {
self.filter = Some(Filter {
condition: "false".into(),
valid: true,
ref_entries: Some(RefEntries { ref_entry: None }),
});
self.speichern = "0".into()
}
}
impl Sortable for Entry {
fn sorting_key(&self) -> String {
self.name.clone()
}
fn sorted(&mut self) -> &Self
where
Self: Sized,
{
if let Some(ref mut filter) = self.filter {
if let Some(ref mut ref_entries) = filter.ref_entries {
if let Some(ref mut ref_entry) = ref_entries.ref_entry {
ref_entry.sort_unstable()
}
}
}
self
}
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]

View File

@@ -50,6 +50,8 @@ pub struct Form {
pub name: String, pub name: String,
#[serde(default)] #[serde(default)]
pub form_references: Vec<FormReference>, pub form_references: Vec<FormReference>,
#[serde(default)]
pub form_fields: Vec<FormField>,
pub menu_category: Option<MenuCategory>, pub menu_category: Option<MenuCategory>,
} }
@@ -68,6 +70,13 @@ impl FormReference {
} }
} }
#[derive(Deserialize)]
pub struct FormField {
pub name: String,
#[serde(default)]
pub hide: bool,
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct MenuCategory { pub struct MenuCategory {
pub name: String, pub name: String,
@@ -93,6 +102,9 @@ mod tests {
referenced_data_form: 'OS.Tumorkonferenz.VarianteUKW' referenced_data_form: 'OS.Tumorkonferenz.VarianteUKW'
anzeige: 'Datum: {Datum}' anzeige: 'Datum: {Datum}'
anzeige_auswahl: 'TK vom {Datum}' anzeige_auswahl: 'TK vom {Datum}'
form_fields:
- name: eingabefeld
hide: true
"; ";
match Profile::from_str(content) { match Profile::from_str(content) {
@@ -101,6 +113,7 @@ mod tests {
assert_eq!(profile.forms[0].name, "DNPM Therapieplan"); assert_eq!(profile.forms[0].name, "DNPM Therapieplan");
assert!(profile.forms[0].menu_category.is_some()); assert!(profile.forms[0].menu_category.is_some());
assert_eq!(profile.forms[0].form_references.len(), 1); assert_eq!(profile.forms[0].form_references.len(), 1);
assert_eq!(profile.forms[0].form_fields.len(), 1)
} }
Err(e) => panic!("Cannot deserialize profile: {}", e), Err(e) => panic!("Cannot deserialize profile: {}", e),
} }
@@ -212,4 +225,29 @@ mod tests {
let actual = Profile::from_str(content); let actual = Profile::from_str(content);
assert!(actual.is_err()); assert!(actual.is_err());
} }
#[test]
fn should_deserialize_form_fields() {
let content = "forms:
- name: 'DNPM Therapieplan'
form_fields:
- name: formularfeld_to_keep
hide: false
- name: formularfeld_to_hide
hide: true
";
match Profile::from_str(content) {
Ok(profile) => {
assert_eq!(profile.forms.len(), 1);
assert_eq!(profile.forms[0].name, "DNPM Therapieplan");
assert_eq!(profile.forms[0].form_fields.len(), 2);
assert_eq!(profile.forms[0].form_fields[0].name, "formularfeld_to_keep");
assert!(!profile.forms[0].form_fields[0].hide);
assert_eq!(profile.forms[0].form_fields[1].name, "formularfeld_to_hide");
assert!(profile.forms[0].form_fields[1].hide);
}
Err(e) => panic!("Cannot deserialize profile: {}", e),
}
}
} }