diff --git a/agent_based/inv_juniper_hw_modules.py b/agent_based/inv_juniper_hw_modules.py
index 842c215d7b9f58608b168ee55dcbd860d25aaf95..9ed6bb7b13b8f7f68d2272ae7720b012d4ade893 100644
--- a/agent_based/inv_juniper_hw_modules.py
+++ b/agent_based/inv_juniper_hw_modules.py
@@ -9,10 +9,11 @@
 #
 # inventory of juniper hardware modules
 #
+# 2023-06-03: moved gui files to ~/local/lib/chek_mk/gui/plugins/...
+# 2023-06-03: fixed KeyError: 'serial_number'
+#
 
-
-import time
-from typing import List, NamedTuple, Optional, Dict
+from typing import List, Dict
 
 from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
     StringTable,
@@ -31,7 +32,7 @@ def parse_inv_juniper_hw_modules(string_table: List[StringTable]) -> List[Dict]:
     modules = []
 
     jnx_contents_entry, jnx_box_anatomy, sys_uptime = string_table
-    sys_uptime = int(sys_uptime[0][0]) / 100  # change to seconds
+    # sys_uptime = int(sys_uptime[0][0]) / 100  # change to seconds
     # first entry in jnx_contents_entry is the chassis without data (?)
     if jnx_contents_entry[0][5:9] == ['', '', '', '0']:
         box_class, box_descr, box_serial_no, box_revision, box_installed = jnx_box_anatomy[0]
@@ -44,7 +45,7 @@ def parse_inv_juniper_hw_modules(string_table: List[StringTable]) -> List[Dict]:
         chassis_id, chassis_descr, chassis_clei_code, model in jnx_contents_entry:
 
         index = f'{container_index}.{l1_index}.{l2_index}.{l3_index}'
-        installed = time.ctime(time.time() - sys_uptime + (int(installed))) if installed != '0' else None
+        # installed = time.ctime(time.time() - sys_uptime + (int(installed))) if installed != '0' else None
 
         module = {}
         for key, value in [
@@ -76,7 +77,7 @@ def inventory_hw_modules(params, section: List[Dict]) -> InventoryResult:
 
     for module in section:
         # do not add parts without serial number
-        if allparts is False and module['serial_number'] is None:
+        if allparts is False and module.get('serial_number') is None:
             continue
 
         key_columns = {'index': module['index']}
diff --git a/gui/views/inv_juniper_hw_modules.py b/gui/views/inv_juniper_hw_modules.py
new file mode 100644
index 0000000000000000000000000000000000000000..f3e92fd6fe5bdf291ba513c055822031cdfd1b28
--- /dev/null
+++ b/gui/views/inv_juniper_hw_modules.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2022-06-02
+#
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.views.utils import (
+    inventory_displayhints,
+)
+from cmk.gui.plugins.views.inventory import (
+    declare_invtable_view,
+)
+
+inventory_displayhints.update({
+    '.hardware.juniper-hw-modules:': {'title': _('Modules'),
+                                      'keyorder': ['index', 'description', 'serial_number', 'revision', 'part_no', ],
+                                      'view': 'invmodules_of_host',
+                                      },
+    '.hardware.juniper-hw-modules:*.index': {'title': _('Index'), },
+    '.hardware.juniper-hw-modules:*.serial_number': {'title': _('Serial number')},
+    '.hardware.juniper-hw-modules:*.description': {'title': _('Description')},
+    '.hardware.juniper-hw-modules:*.revision': {'title': _('Revision'), },
+    '.hardware.juniper-hw-modules:*.installed_at': {'title': _('Installed at'), },
+    '.hardware.juniper-hw-modules:*.part_no': {'title': _('Part No'), },
+    '.hardware.juniper-hw-modules:*.chassis_id': {'title': _('Chassis ID'), },
+    '.hardware.juniper-hw-modules:*.chassis_descr': {'title': _('Chassis description')},
+    '.hardware.juniper-hw-modules:*.chassis_clei_code': {'title': _('Chassis CLEI code'), },
+    '.hardware.juniper-hw-modules:*.model': {'title': _('Model'), },
+    '.hardware.juniper-hw-modules:*.type': {'title': _('Type (OID)'), },
+})
+
+declare_invtable_view(
+    'invmodules',
+    '.hardware.juniper-hw-modules:',
+    _('Juniper Hardware Modules'),
+    _('Juniper Hardware Modules')
+)
diff --git a/gui/wato/inv_juniper_hw_modules.py b/gui/wato/inv_juniper_hw_modules.py
new file mode 100644
index 0000000000000000000000000000000000000000..45e866616d65f37fd7bb75dd257a0aa7ce90bcc7
--- /dev/null
+++ b/gui/wato/inv_juniper_hw_modules.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# License: GNU General Public License v2
+#
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
+# Date  : 2022-06-02
+#
+
+from cmk.gui.i18n import _
+from cmk.gui.plugins.wato.utils import (
+    HostRulespec,
+    rulespec_registry,
+)
+from cmk.gui.valuespec import (
+    Dictionary,
+    FixedValue,
+    ListChoice,
+)
+
+from cmk.gui.plugins.wato.inventory import (
+    RulespecGroupInventory,
+)
+
+_removecolumns = [
+    ('chassis_clei_code', 'Chassis CLEI code'),
+    ('chassis_descr', 'Chassis description'),
+    ('chassis_id', 'Chassis ID'),
+    # ('installed_at', 'Installed at'),
+    ('model', 'Model'),
+    ('type', 'Type (OID)'),
+]
+
+
+def _valuespec_inv_juniper_hw_modules():
+    return Dictionary(
+        title=_('Juniper hardware inventory'),
+        elements=[
+            ('allparts',
+             FixedValue(
+                 True,
+                 title=_('Inventory parts without serial number'),
+                 totext=_(''),
+                 default_value=False,
+             )),
+            ('removecolumns',
+             ListChoice(
+                 title=_('List of columns to remove'),
+                 help=_('information to remove from inventory'),
+                 choices=_removecolumns,
+                 default_value=[
+                 ],
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupInventory,
+        match_type="dict",
+        name="inv_parameters:inv_juniper_hw_modules",
+        valuespec=_valuespec_inv_juniper_hw_modules,
+    ))
diff --git a/inv_juniper_hw_modules-0.02-20230603.mkp b/inv_juniper_hw_modules-0.02-20230603.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..fe2581d20b321de4a22b447ba15d945d096f0c15
Binary files /dev/null and b/inv_juniper_hw_modules-0.02-20230603.mkp differ
diff --git a/inv_juniper_hw_modules.mkp b/inv_juniper_hw_modules.mkp
index db46a7256243cc2aa4207c7f7ff9ad26c2b4b300..fe2581d20b321de4a22b447ba15d945d096f0c15 100644
Binary files a/inv_juniper_hw_modules.mkp and b/inv_juniper_hw_modules.mkp differ
diff --git a/packages/inv_juniper_hw_modules b/packages/inv_juniper_hw_modules
index 7f722a6b2b03bf6befb447b2232748ad5cfcd7e7..cb0413e9c8b5ef97b62e3c128d38cc04444af2ab 100644
--- a/packages/inv_juniper_hw_modules
+++ b/packages/inv_juniper_hw_modules
@@ -2,12 +2,11 @@
  'description': 'Inventory of Juniper networks hardware modules\n',
  'download_url': 'https://thl-cmk.hopto.org',
  'files': {'agent_based': ['inv_juniper_hw_modules.py'],
-           'web': ['plugins/views/inv_juniper_hw_modules.py',
-                   'plugins/wato/inv_juniper_hw_modules.py']},
+           'gui': ['views/inv_juniper_hw_modules.py',
+                   'wato/inv_juniper_hw_modules.py']},
  'name': 'inv_juniper_hw_modules',
- 'num_files': 3,
  'title': 'Juniper networks hardware inventory',
- 'version': '20220602.v.0.01',
- 'version.min_required': '2.0.0',
- 'version.packaged': '2021.09.20',
+ 'version': '0.02-20230603',
+ 'version.min_required': '2.1.0b1',
+ 'version.packaged': '2.1.0p21',
  'version.usable_until': None}
\ No newline at end of file