feedback-hub 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- feedback_hub-1.0.0/.github/workflows/publish.yml +28 -0
- feedback_hub-1.0.0/.gitignore +8 -0
- feedback_hub-1.0.0/INTEGRATING.md +127 -0
- feedback_hub-1.0.0/LICENSE +21 -0
- feedback_hub-1.0.0/PKG-INFO +52 -0
- feedback_hub-1.0.0/README.md +9 -0
- feedback_hub-1.0.0/docs/PUBLISHING.md +38 -0
- feedback_hub-1.0.0/pyproject.toml +37 -0
- feedback_hub-1.0.0/schemas/chapterforge.json +67 -0
- feedback_hub-1.0.0/schemas/glow.json +52 -0
- feedback_hub-1.0.0/schemas/quill.json +65 -0
- feedback_hub-1.0.0/src/feedback_hub/__init__.py +117 -0
- feedback_hub-1.0.0/src/feedback_hub/_github.py +148 -0
- feedback_hub-1.0.0/src/feedback_hub/_schema.py +160 -0
- feedback_hub-1.0.0/src/feedback_hub/_storage.py +137 -0
- feedback_hub-1.0.0/src/feedback_hub/compat_glow.py +91 -0
- feedback_hub-1.0.0/src/feedback_hub/flask_blueprint.py +267 -0
- feedback_hub-1.0.0/src/feedback_hub/wx_dialog.py +246 -0
- feedback_hub-1.0.0/tests/test_github.py +75 -0
- feedback_hub-1.0.0/tests/test_schema.py +76 -0
- feedback_hub-1.0.0/tests/test_storage.py +56 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
publish:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
environment: pypi
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write # required for OIDC trusted publisher
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Build package
|
|
23
|
+
run: |
|
|
24
|
+
python -m pip install build
|
|
25
|
+
python -m build
|
|
26
|
+
|
|
27
|
+
- name: Publish to PyPI
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Integrating feedback-hub
|
|
2
|
+
|
|
3
|
+
## ChapterForge (wxPython)
|
|
4
|
+
|
|
5
|
+
### 1. Add to requirements
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
feedback-hub>=1.0
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
### 2. Add menu item to Help menu in app.py
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
# In the Help menu setup:
|
|
15
|
+
report_item = help_menu.Append(wx.ID_ANY, "Report an Issue")
|
|
16
|
+
self.Bind(wx.EVT_MENU, self.on_report_issue, report_item)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 3. Add handler
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
def on_report_issue(self, _event):
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from feedback_hub import load_schema
|
|
25
|
+
from feedback_hub.wx_dialog import FeedbackDialog
|
|
26
|
+
|
|
27
|
+
schema = load_schema(Path(__file__).parent / "schemas" / "chapterforge.json")
|
|
28
|
+
dlg = FeedbackDialog(
|
|
29
|
+
self,
|
|
30
|
+
schema=schema,
|
|
31
|
+
github_token=CHAPTERFORGE_GITHUB_TOKEN, # bundled fine-grained PAT
|
|
32
|
+
app_version=__version__,
|
|
33
|
+
)
|
|
34
|
+
dlg.ShowModal()
|
|
35
|
+
dlg.Destroy()
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 4. Token setup
|
|
39
|
+
|
|
40
|
+
Create a GitHub fine-grained PAT:
|
|
41
|
+
- Go to GitHub Settings > Developer Settings > Personal Access Tokens > Fine-grained
|
|
42
|
+
- Repository access: BITS-ACB/chapterforge only
|
|
43
|
+
- Permissions: Issues = Read and Write (everything else = None)
|
|
44
|
+
- Store as `CHAPTERFORGE_GITHUB_TOKEN` in a config or bundle in the app
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## GLOW (Flask) - Non-breaking migration
|
|
49
|
+
|
|
50
|
+
### 1. Add to requirements.txt
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
feedback-hub>=1.0
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 2. Replace feedback.py (one line change)
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
# web/src/acb_large_print_web/routes/feedback.py
|
|
60
|
+
# Replace entire file with:
|
|
61
|
+
from feedback_hub.compat_glow import feedback_bp
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 3. Any code importing from support_hub still works
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
# This still works unchanged:
|
|
68
|
+
from acb_large_print_web.support_hub import create_support_issue, load_support_hub_config
|
|
69
|
+
# OR directly:
|
|
70
|
+
from feedback_hub.compat_glow import create_support_issue, load_support_hub_config
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 4. Environment variables
|
|
74
|
+
|
|
75
|
+
No changes. GLOW's existing env vars still work:
|
|
76
|
+
- `FEEDBACK_GITHUB_TOKEN`
|
|
77
|
+
- `FEEDBACK_GITHUB_REPO`
|
|
78
|
+
- `FEEDBACK_GITHUB_LABELS`
|
|
79
|
+
- `FEEDBACK_GITHUB_ASSIGNEE`
|
|
80
|
+
- `FEEDBACK_PASSWORD`
|
|
81
|
+
- `FEEDBACK_API_TOKEN`
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## QUILL (wxPython)
|
|
86
|
+
|
|
87
|
+
Same pattern as ChapterForge. Replace `report_bug()` in main_frame.py:
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
def report_bug(self) -> None:
|
|
91
|
+
from pathlib import Path
|
|
92
|
+
from feedback_hub import load_schema
|
|
93
|
+
from feedback_hub.wx_dialog import FeedbackDialog
|
|
94
|
+
|
|
95
|
+
schema = load_schema(Path(__file__).parent.parent / "schemas" / "quill.json")
|
|
96
|
+
dlg = FeedbackDialog(
|
|
97
|
+
self.frame,
|
|
98
|
+
schema=schema,
|
|
99
|
+
github_token=QUILL_GITHUB_TOKEN,
|
|
100
|
+
app_version=__version__,
|
|
101
|
+
)
|
|
102
|
+
result = dlg.ShowModal()
|
|
103
|
+
dlg.Destroy()
|
|
104
|
+
if result == wx.ID_OK:
|
|
105
|
+
self._set_status("Bug report submitted")
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
This replaces the clipboard+browser approach with direct GitHub submission.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Token Security Notes
|
|
113
|
+
|
|
114
|
+
**Fine-grained PATs with issues:write only are safe to bundle in desktop apps.**
|
|
115
|
+
|
|
116
|
+
- Scope: issues:write on ONE repo only
|
|
117
|
+
- Worst-case misuse: someone files extra issues in your repo
|
|
118
|
+
- Cannot access code, other repos, account settings, or billing
|
|
119
|
+
- Rotate annually or if compromised
|
|
120
|
+
|
|
121
|
+
**Server apps (GLOW):** Token stays in `.env`, never touches clients.
|
|
122
|
+
|
|
123
|
+
**Desktop apps (ChapterForge, QUILL):** Bundle a fine-grained PAT.
|
|
124
|
+
```python
|
|
125
|
+
# In your app's constants or settings:
|
|
126
|
+
CHAPTERFORGE_GITHUB_TOKEN = "github_pat_..." # issues:write on BITS-ACB/chapterforge only
|
|
127
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Blind Information Technology Solutions (BITS)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: feedback-hub
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Multi-framework GitHub issue submission library - native UI per framework, centralized GitHub backend
|
|
5
|
+
Project-URL: Homepage, https://github.com/community-access/feedback-hub
|
|
6
|
+
Project-URL: Documentation, https://community-access.github.io/feedback-hub
|
|
7
|
+
Project-URL: Repository, https://github.com/community-access/feedback-hub
|
|
8
|
+
Project-URL: Issues, https://github.com/community-access/feedback-hub/issues
|
|
9
|
+
Author-email: "Blind Information Technology Solutions (BITS)" <info@chapterforge.org>
|
|
10
|
+
License: MIT License
|
|
11
|
+
|
|
12
|
+
Copyright (c) 2026 Blind Information Technology Solutions (BITS)
|
|
13
|
+
|
|
14
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
15
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
16
|
+
in the Software without restriction, including without limitation the rights
|
|
17
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
18
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
19
|
+
furnished to do so, subject to the following conditions:
|
|
20
|
+
|
|
21
|
+
The above copyright notice and this permission notice shall be included in all
|
|
22
|
+
copies or substantial portions of the Software.
|
|
23
|
+
|
|
24
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
25
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
26
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
27
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
28
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
29
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
30
|
+
SOFTWARE.
|
|
31
|
+
License-File: LICENSE
|
|
32
|
+
Requires-Python: >=3.10
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: flask>=3.0; extra == 'dev'
|
|
35
|
+
Requires-Dist: hatch; extra == 'dev'
|
|
36
|
+
Requires-Dist: pytest-cov; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
38
|
+
Provides-Extra: flask
|
|
39
|
+
Requires-Dist: flask>=3.0; extra == 'flask'
|
|
40
|
+
Provides-Extra: wx
|
|
41
|
+
Requires-Dist: wxpython>=4.2; extra == 'wx'
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
# feedback-hub
|
|
45
|
+
|
|
46
|
+
Multi-framework GitHub issue submission library. Native UI per framework, centralized GitHub backend.
|
|
47
|
+
|
|
48
|
+
- **wxPython apps** (ChapterForge, QUILL): native dialog, direct GitHub submission
|
|
49
|
+
- **Flask apps** (GLOW): web form, direct GitHub submission
|
|
50
|
+
- **CLI / headless**: function call, direct GitHub submission
|
|
51
|
+
|
|
52
|
+
See [INTEGRATING.md](INTEGRATING.md) for integration guides.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# feedback-hub
|
|
2
|
+
|
|
3
|
+
Multi-framework GitHub issue submission library. Native UI per framework, centralized GitHub backend.
|
|
4
|
+
|
|
5
|
+
- **wxPython apps** (ChapterForge, QUILL): native dialog, direct GitHub submission
|
|
6
|
+
- **Flask apps** (GLOW): web form, direct GitHub submission
|
|
7
|
+
- **CLI / headless**: function call, direct GitHub submission
|
|
8
|
+
|
|
9
|
+
See [INTEGRATING.md](INTEGRATING.md) for integration guides.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Publishing feedback-hub to PyPI
|
|
2
|
+
|
|
3
|
+
## Step 1 - Create a PyPI account
|
|
4
|
+
|
|
5
|
+
Go to https://pypi.org/account/register/ and create an account for the BITS org (or use an existing one). Verify your email.
|
|
6
|
+
|
|
7
|
+
## Step 2 - Configure a Trusted Publisher (no token needed)
|
|
8
|
+
|
|
9
|
+
This is the modern approach - GitHub Actions authenticates directly with PyPI via OIDC, no API token to rotate.
|
|
10
|
+
|
|
11
|
+
1. Go to https://pypi.org/manage/account/publishing/
|
|
12
|
+
2. Under **Add a new pending publisher**, fill in:
|
|
13
|
+
- **PyPI project name**: `feedback-hub`
|
|
14
|
+
- **Owner**: `Community-Access`
|
|
15
|
+
- **Repository**: `feedback-hub`
|
|
16
|
+
- **Workflow name**: `publish.yml`
|
|
17
|
+
- **Environment**: `pypi`
|
|
18
|
+
3. Click **Add**
|
|
19
|
+
|
|
20
|
+
## Step 3 - Create the `pypi` environment in GitHub
|
|
21
|
+
|
|
22
|
+
1. Go to https://github.com/Community-Access/feedback-hub/settings/environments
|
|
23
|
+
2. Click **New environment**, name it `pypi`
|
|
24
|
+
3. No secrets needed - the OIDC trust handles auth
|
|
25
|
+
|
|
26
|
+
## Step 4 - Create a GitHub release to trigger the publish
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
gh release create v1.0.0 --repo Community-Access/feedback-hub \
|
|
30
|
+
--title "feedback-hub 1.0.0" \
|
|
31
|
+
--notes "Initial public release."
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
This triggers `publish.yml`, which builds the package and uploads it to PyPI. The package will be live at https://pypi.org/project/feedback-hub/ within a minute or two.
|
|
35
|
+
|
|
36
|
+
## Step 5 - Fix ChapterForge CI
|
|
37
|
+
|
|
38
|
+
Once it's on PyPI, the existing `requirements.txt` entry (`feedback-hub>=1.0`) works as-is and CI will pass.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "feedback-hub"
|
|
7
|
+
version = "1.0.0"
|
|
8
|
+
description = "Multi-framework GitHub issue submission library - native UI per framework, centralized GitHub backend"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { file = "LICENSE" }
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Blind Information Technology Solutions (BITS)", email = "info@chapterforge.org" }
|
|
13
|
+
]
|
|
14
|
+
requires-python = ">=3.10"
|
|
15
|
+
dependencies = [] # zero hard dependencies - wx and flask are optional
|
|
16
|
+
|
|
17
|
+
[project.optional-dependencies]
|
|
18
|
+
flask = ["flask>=3.0"]
|
|
19
|
+
wx = ["wxPython>=4.2"]
|
|
20
|
+
dev = [
|
|
21
|
+
"pytest>=8.0",
|
|
22
|
+
"pytest-cov",
|
|
23
|
+
"flask>=3.0",
|
|
24
|
+
"hatch",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://github.com/community-access/feedback-hub"
|
|
29
|
+
Documentation = "https://community-access.github.io/feedback-hub"
|
|
30
|
+
Repository = "https://github.com/community-access/feedback-hub"
|
|
31
|
+
Issues = "https://github.com/community-access/feedback-hub/issues"
|
|
32
|
+
|
|
33
|
+
[tool.hatch.build.targets.wheel]
|
|
34
|
+
packages = ["src/feedback_hub"]
|
|
35
|
+
|
|
36
|
+
[tool.pytest.ini_options]
|
|
37
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "ChapterForge",
|
|
3
|
+
"github_repo": "BITS-ACB/chapterforge",
|
|
4
|
+
"github_labels": ["bug", "needs-triage"],
|
|
5
|
+
"github_assignee": "",
|
|
6
|
+
"categories": [
|
|
7
|
+
"Bug Report",
|
|
8
|
+
"Feature Request",
|
|
9
|
+
"Accessibility Issue",
|
|
10
|
+
"Documentation",
|
|
11
|
+
"Other"
|
|
12
|
+
],
|
|
13
|
+
"fields": [
|
|
14
|
+
{
|
|
15
|
+
"name": "summary",
|
|
16
|
+
"label": "Summary",
|
|
17
|
+
"type": "text",
|
|
18
|
+
"required": true,
|
|
19
|
+
"max_length": 120,
|
|
20
|
+
"placeholder": "Brief description of the issue"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "message",
|
|
24
|
+
"label": "What happened",
|
|
25
|
+
"type": "textarea",
|
|
26
|
+
"required": true,
|
|
27
|
+
"max_length": 5000,
|
|
28
|
+
"placeholder": "Describe the issue in detail"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "expected",
|
|
32
|
+
"label": "What you expected",
|
|
33
|
+
"type": "textarea",
|
|
34
|
+
"required": false,
|
|
35
|
+
"max_length": 2000
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "steps",
|
|
39
|
+
"label": "Steps to reproduce",
|
|
40
|
+
"type": "textarea",
|
|
41
|
+
"required": false,
|
|
42
|
+
"max_length": 2000,
|
|
43
|
+
"placeholder": "1. Open folder...\n2. Click Build..."
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"name": "version",
|
|
47
|
+
"label": "ChapterForge version",
|
|
48
|
+
"type": "text",
|
|
49
|
+
"required": false,
|
|
50
|
+
"default": "__app_version__"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"name": "platform",
|
|
54
|
+
"label": "Operating system",
|
|
55
|
+
"type": "text",
|
|
56
|
+
"required": false,
|
|
57
|
+
"default": "__platform__"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "screenreader",
|
|
61
|
+
"label": "Screen reader (if any)",
|
|
62
|
+
"type": "text",
|
|
63
|
+
"required": false,
|
|
64
|
+
"placeholder": "e.g. NVDA 2024.1, JAWS, or None"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "GLOW",
|
|
3
|
+
"github_repo": "Community-Access/support",
|
|
4
|
+
"github_labels": ["needs-triage"],
|
|
5
|
+
"github_assignee": "",
|
|
6
|
+
"categories": [
|
|
7
|
+
"Bug Report",
|
|
8
|
+
"Feature Request",
|
|
9
|
+
"Accessibility Issue",
|
|
10
|
+
"Document Conversion",
|
|
11
|
+
"Braille",
|
|
12
|
+
"Documentation",
|
|
13
|
+
"Other"
|
|
14
|
+
],
|
|
15
|
+
"fields": [
|
|
16
|
+
{
|
|
17
|
+
"name": "summary",
|
|
18
|
+
"label": "Summary",
|
|
19
|
+
"type": "text",
|
|
20
|
+
"required": true,
|
|
21
|
+
"max_length": 120
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "message",
|
|
25
|
+
"label": "Details",
|
|
26
|
+
"type": "textarea",
|
|
27
|
+
"required": true,
|
|
28
|
+
"max_length": 5000
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "task",
|
|
32
|
+
"label": "What were you trying to do",
|
|
33
|
+
"type": "text",
|
|
34
|
+
"required": false,
|
|
35
|
+
"max_length": 240
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"name": "version",
|
|
39
|
+
"label": "GLOW version",
|
|
40
|
+
"type": "text",
|
|
41
|
+
"required": false,
|
|
42
|
+
"default": "__app_version__"
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "platform",
|
|
46
|
+
"label": "Browser / OS",
|
|
47
|
+
"type": "text",
|
|
48
|
+
"required": false,
|
|
49
|
+
"default": "__platform__"
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app": "Quill",
|
|
3
|
+
"github_repo": "Community-Access/quill",
|
|
4
|
+
"github_labels": ["bug", "needs-triage"],
|
|
5
|
+
"github_assignee": "",
|
|
6
|
+
"categories": [
|
|
7
|
+
"Bug Report",
|
|
8
|
+
"Feature Request",
|
|
9
|
+
"Accessibility Issue",
|
|
10
|
+
"Documentation",
|
|
11
|
+
"Other"
|
|
12
|
+
],
|
|
13
|
+
"fields": [
|
|
14
|
+
{
|
|
15
|
+
"name": "summary",
|
|
16
|
+
"label": "Summary",
|
|
17
|
+
"type": "text",
|
|
18
|
+
"required": true,
|
|
19
|
+
"max_length": 120,
|
|
20
|
+
"default": "Bug report"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "message",
|
|
24
|
+
"label": "What happened",
|
|
25
|
+
"type": "textarea",
|
|
26
|
+
"required": true,
|
|
27
|
+
"max_length": 5000
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "expected",
|
|
31
|
+
"label": "What you expected",
|
|
32
|
+
"type": "textarea",
|
|
33
|
+
"required": false,
|
|
34
|
+
"max_length": 2000
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"name": "steps",
|
|
38
|
+
"label": "Steps to reproduce",
|
|
39
|
+
"type": "textarea",
|
|
40
|
+
"required": false,
|
|
41
|
+
"max_length": 2000
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "version",
|
|
45
|
+
"label": "Quill version",
|
|
46
|
+
"type": "text",
|
|
47
|
+
"required": false,
|
|
48
|
+
"default": "__app_version__"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"name": "platform",
|
|
52
|
+
"label": "Operating system",
|
|
53
|
+
"type": "text",
|
|
54
|
+
"required": false,
|
|
55
|
+
"default": "__platform__"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"name": "screenreader",
|
|
59
|
+
"label": "Screen reader (if any)",
|
|
60
|
+
"type": "text",
|
|
61
|
+
"required": false,
|
|
62
|
+
"placeholder": "e.g. NVDA 2024.1, JAWS, or None"
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""feedback-hub - Multi-framework GitHub issue submission library.
|
|
2
|
+
|
|
3
|
+
Each app uses its native UI; all submit directly to GitHub Issues.
|
|
4
|
+
|
|
5
|
+
Quick start (wxPython)::
|
|
6
|
+
|
|
7
|
+
from feedback_hub import load_schema
|
|
8
|
+
from feedback_hub.wx_dialog import FeedbackDialog
|
|
9
|
+
|
|
10
|
+
schema = load_schema({"app": "MyApp", "github_repo": "org/repo", "fields": [...]})
|
|
11
|
+
dlg = FeedbackDialog(parent, schema=schema, github_token=TOKEN)
|
|
12
|
+
dlg.ShowModal()
|
|
13
|
+
dlg.Destroy()
|
|
14
|
+
|
|
15
|
+
Quick start (Flask)::
|
|
16
|
+
|
|
17
|
+
from feedback_hub.flask_blueprint import make_blueprint
|
|
18
|
+
|
|
19
|
+
feedback_bp = make_blueprint(app_name="MyApp", github_repo="org/repo")
|
|
20
|
+
app.register_blueprint(feedback_bp, url_prefix="/feedback")
|
|
21
|
+
|
|
22
|
+
Quick start (headless / CLI)::
|
|
23
|
+
|
|
24
|
+
from feedback_hub import submit
|
|
25
|
+
|
|
26
|
+
issue_url, error = submit(
|
|
27
|
+
app="MyApp",
|
|
28
|
+
github_repo="org/repo",
|
|
29
|
+
github_token=TOKEN,
|
|
30
|
+
summary="Something is broken",
|
|
31
|
+
message="Details here",
|
|
32
|
+
category="Bug Report",
|
|
33
|
+
)
|
|
34
|
+
"""
|
|
35
|
+
from feedback_hub._github import GitHubConfig, resolve_token
|
|
36
|
+
from feedback_hub._schema import AppSchema, FieldSchema, build_entry, load_schema
|
|
37
|
+
from feedback_hub._storage import list_all, save
|
|
38
|
+
|
|
39
|
+
__version__ = "1.0.0"
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"AppSchema",
|
|
43
|
+
"FieldSchema",
|
|
44
|
+
"GitHubConfig",
|
|
45
|
+
"build_entry",
|
|
46
|
+
"list_all",
|
|
47
|
+
"load_schema",
|
|
48
|
+
"resolve_token",
|
|
49
|
+
"save",
|
|
50
|
+
"submit",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def submit(
|
|
55
|
+
*,
|
|
56
|
+
app: str,
|
|
57
|
+
github_repo: str,
|
|
58
|
+
github_token: str = "",
|
|
59
|
+
summary: str = "",
|
|
60
|
+
message: str,
|
|
61
|
+
category: str = "feedback",
|
|
62
|
+
name: str = "",
|
|
63
|
+
email: str = "",
|
|
64
|
+
app_version: str = "",
|
|
65
|
+
github_labels: list[str] | None = None,
|
|
66
|
+
github_assignee: str = "",
|
|
67
|
+
metadata: dict | None = None,
|
|
68
|
+
db_path=None,
|
|
69
|
+
) -> tuple:
|
|
70
|
+
"""Headless submission -- no UI required.
|
|
71
|
+
|
|
72
|
+
Returns ``(issue_url, error_message)``.
|
|
73
|
+
"""
|
|
74
|
+
from datetime import UTC, datetime
|
|
75
|
+
from pathlib import Path
|
|
76
|
+
|
|
77
|
+
from feedback_hub._github import create_issue
|
|
78
|
+
from feedback_hub._storage import save as _save, update_github_sync
|
|
79
|
+
|
|
80
|
+
token = resolve_token(github_token)
|
|
81
|
+
entry = {
|
|
82
|
+
"app": app,
|
|
83
|
+
"version": app_version,
|
|
84
|
+
"platform": "",
|
|
85
|
+
"category": category,
|
|
86
|
+
"name": name,
|
|
87
|
+
"email": email,
|
|
88
|
+
"summary": summary,
|
|
89
|
+
"message": message,
|
|
90
|
+
"metadata": metadata,
|
|
91
|
+
"timestamp": datetime.now(UTC).isoformat(),
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_db = db_path or Path.home() / ".local" / "share" / "feedback-hub" / "feedback.db"
|
|
95
|
+
try:
|
|
96
|
+
row_id = _save(entry, Path(_db))
|
|
97
|
+
except Exception:
|
|
98
|
+
row_id = None
|
|
99
|
+
|
|
100
|
+
if not token:
|
|
101
|
+
return None, "GitHub token not configured"
|
|
102
|
+
|
|
103
|
+
cfg = GitHubConfig(
|
|
104
|
+
token=token,
|
|
105
|
+
repo=github_repo,
|
|
106
|
+
assignee=github_assignee,
|
|
107
|
+
labels=github_labels or ["needs-triage"],
|
|
108
|
+
)
|
|
109
|
+
number, url, error = create_issue(entry, cfg)
|
|
110
|
+
|
|
111
|
+
if row_id is not None:
|
|
112
|
+
try:
|
|
113
|
+
update_github_sync(row_id, issue_number=number, issue_url=url, error=error, db_path=Path(_db))
|
|
114
|
+
except Exception:
|
|
115
|
+
pass
|
|
116
|
+
|
|
117
|
+
return url, error
|