diff --git a/.gitignore b/.gitignore
index c6bba59..579267b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -128,3 +128,8 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
+
+*.exe
+resources/rpv-web.ico
+resources/rpv-web.rc
+resources/rpv-web.res
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd90a1e..1eb97d5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## v1.3.0 - July 29, 2024
+
+### Added
+
+* Add RPC interface filter
+* Add support for negative filters
+* Add RPC interface version in interface pane
+* Add module base address to interface details
+
+### Changed
+
+* Make process filter persistent when tab is changed
+* MIDL view now jumps to selected method
+
+
## v1.2.1 - July 19, 2024
### Changed
diff --git a/README.md b/README.md
index 31e2f94..3d642d5 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[![](https://github.com/qtc-de/rpv-web/actions/workflows/build.yml/badge.svg?branch=main)](https://github.com/qtc-de/rpv-web/actions/workflows/build.yml)
[![](https://github.com/qtc-de/rpv-web/actions/workflows/build.yml/badge.svg?branch=dev)](https://github.com/qtc-de/rpv-web/actions/workflows/build.yml)
-[![](https://img.shields.io/badge/version-1.2.1-blue)](https://github.com/qtc-de/rpv-web/releases)
+[![](https://img.shields.io/badge/version-1.3.0-blue)](https://github.com/qtc-de/rpv-web/releases)
[![](https://img.shields.io/badge/language-v%20%26%20vue-blue)](https://vlang.io/)
[![](https://img.shields.io/badge/license-GPL%20v3.0-blue)](https://github.com/qtc-de/rpv-web/blob/master/LICENSE)
[![](https://img.shields.io/badge/Pages-fa6b05)](https://qtc-de.github.io/rpv-web/)
diff --git a/frontend/Dockerfile.dev b/frontend/Dockerfile.dev
new file mode 100644
index 0000000..fd695f0
--- /dev/null
+++ b/frontend/Dockerfile.dev
@@ -0,0 +1,19 @@
+FROM node:lts-alpine
+
+WORKDIR /app
+COPY package*.json .
+
+RUN adduser --gecos '' --disabled-password rpv \
+ && chown -R rpv:rpv /app \
+ && su rpv -c "npm install" \
+ && su rpv -c "npm install http-server"
+
+COPY . .
+
+RUN chown -R rpv:rpv /app \
+ && su rpv -c "npm run build"
+
+USER rpv:rpv
+EXPOSE 5173
+
+CMD ["npm", "run", "dev", "--", "--host"]
diff --git a/frontend/dev.sh b/frontend/dev.sh
new file mode 100755
index 0000000..62e1cf7
--- /dev/null
+++ b/frontend/dev.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+podman image exists rpv-web-dev
+
+if [ $? -ne 0 ]; then
+ echo '[+] Building rpv-web-dev image.'
+ podman build -t rpv-web-dev -f Dockerfile.dev .
+else
+ echo '[+] rpv-web-dev image already exists.'
+fi
+
+echo '[+] Starting rpv-web-dev container.'
+podman run -v ${PWD}/src/:/app/src:Z -it -p 5173:5173 rpv-web-dev
diff --git a/frontend/src/components/Headline.vue b/frontend/src/components/Headline.vue
index f06b0ab..1b5ca89 100644
--- a/frontend/src/components/Headline.vue
+++ b/frontend/src/components/Headline.vue
@@ -374,7 +374,7 @@
RP
WEB
- v1.1.0
+ v1.3.0
diff --git a/frontend/src/components/InterfaceDetailPane.vue b/frontend/src/components/InterfaceDetailPane.vue
index 63c85f3..b549e6b 100644
--- a/frontend/src/components/InterfaceDetailPane.vue
+++ b/frontend/src/components/InterfaceDetailPane.vue
@@ -107,9 +107,13 @@
v-on:blur="changeInterfaceName($event)"/>
- DLL |
+ Module |
{{ selectedInterface.location }} |
+
+ Module Base |
+ {{ selectedInterface.module_base }} |
+
Description |
{{ selectedInterface.description }} |
diff --git a/frontend/src/components/InterfacePane.vue b/frontend/src/components/InterfacePane.vue
index 65451d0..d3365e6 100644
--- a/frontend/src/components/InterfacePane.vue
+++ b/frontend/src/components/InterfacePane.vue
@@ -16,11 +16,12 @@
setup()
{
const store = processStore();
- const { selectedProcess, selectedInterface } = storeToRefs(store);
- return { store, selectedProcess, selectedInterface }
+ const { interfaceFilter, selectedProcess, selectedInterface } = storeToRefs(store);
+ return { store, interfaceFilter, selectedProcess, selectedInterface }
},
- components: {
+ components:
+ {
VueSimpleContextMenu,
},
@@ -31,6 +32,114 @@
this.selectedInterface = intf;
},
+ casualFilter(intf, filter)
+ {
+ let inverse = false;
+
+ if (filter.startsWith('!'))
+ {
+ filter = filter.substring(1);
+ inverse = true;
+ }
+
+ return (intf.id.toLowerCase().includes(filter) || intf.location.toLowerCase().includes(filter) ||
+ intf.description.toLowerCase().includes(filter) || intf.name.toLowerCase().includes(filter) ||
+ intf.annotation.toLowerCase().includes(filter)) != inverse;
+ },
+
+ getInterfaces: function*(filter)
+ {
+ for (const intf of this.selectedProcess.rpc_info.interface_infos)
+ {
+ if (filter)
+ {
+ let match = true;
+ filter = filter.toLowerCase();
+
+ if (!filter.includes(':') && !this.casualFilter(intf, filter))
+ {
+ match = false;
+ }
+
+ else
+ {
+ const filterArray = filter.split(/\s*\|\s*/);
+
+ for (const entry of filterArray)
+ {
+ let key, value;
+ let inverse = false;
+
+ [key, value] = entry.split(':', 2);
+
+ if (key === 'uuid')
+ {
+ key = 'id';
+ }
+
+ if (value === undefined)
+ {
+ if (!this.casualFilter(intf, key))
+ {
+ match = false;
+ break;
+ }
+
+ continue;
+ }
+
+ if (value.startsWith('!'))
+ {
+ value = value.substring(1);
+ inverse = true;
+ }
+
+ if (Object.hasOwn(intf, key))
+ {
+ const propValue = intf[key];
+
+ if (Array.isArray(propValue))
+ {
+ let found = false;
+
+ for (const item of propValue)
+ {
+ if (String(item).toLowerCase().includes(value))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found != inverse)
+ {
+ match = false;
+ break;
+ }
+ }
+
+ else
+ {
+ if (String(propValue).toLowerCase().includes(value) == inverse)
+ {
+ match = false;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (!match)
+ {
+ continue;
+ }
+ }
+
+ yield intf;
+ }
+ },
+
interfaceClick(e, item)
{
if (item.typ != 'rpc')
@@ -63,11 +172,15 @@
RPC Interfaces
+
+
+