Skip to content

Commit 59d06b7

Browse files
Merge pull request #74 from inventree/react-deps
React deps
2 parents 108bbb4 + 578ba0f commit 59d06b7

File tree

5 files changed

+99
-63
lines changed

5 files changed

+99
-63
lines changed

plugin_creator/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# -*- coding: utf-8 -*-
22

3-
PLUGIN_CREATOR_VERSION = "1.10.0"
3+
PLUGIN_CREATOR_VERSION = "1.11.0"

plugin_creator/cli.py

Lines changed: 59 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@
1414

1515
def default_values() -> dict:
1616
"""Read default values out from the cookiecutter.json file."""
17-
fn = os.path.join(os.path.dirname(__file__), 'template', 'cookiecutter.json')
17+
fn = os.path.join(os.path.dirname(__file__), "template", "cookiecutter.json")
1818

19-
with open(fn, encoding='utf-8') as f:
20-
return json.load(f)
19+
with open(fn, encoding="utf-8") as f:
20+
data = json.load(f)
21+
22+
data["frontend"] = frontend.define_frontend(True, defaults=True)
23+
24+
return data
2125

2226

2327
def gather_info(context: dict) -> dict:
@@ -31,168 +35,163 @@ def gather_info(context: dict) -> dict:
3135
- Package name: The Python package name for the plugin (e.g., "custom_plugin").
3236
- Distribution name: The name used for the Python package distribution (e.g., "inventree-custom-plugin").
3337
"""
34-
info('Enter project information:')
38+
info("Enter project information:")
3539

3640
# Basic project information
37-
context['plugin_title'] = (
41+
context["plugin_title"] = (
3842
questionary.text(
39-
'Enter plugin name',
40-
default=context['plugin_title'],
43+
"Enter plugin name",
44+
default=context["plugin_title"],
4145
validate=validators.ProjectNameValidator,
4246
)
4347
.ask()
4448
.strip()
4549
)
4650

47-
context['plugin_description'] = (
51+
context["plugin_description"] = (
4852
questionary.text(
49-
'Enter plugin description',
50-
default=context['plugin_description'],
53+
"Enter plugin description",
54+
default=context["plugin_description"],
5155
validate=validators.NotEmptyValidator,
5256
)
5357
.ask()
5458
.strip()
5559
)
5660

57-
context['plugin_name'] = context['plugin_title'].replace(' ', '')
61+
context["plugin_name"] = context["plugin_title"].replace(" ", "")
5862

5963
# Convert the project name to a package name
6064
# e.g. 'Custom Plugin' -> 'custom_plugin'
61-
context['plugin_slug'] = context['plugin_title'].replace(' ', '-').lower()
62-
context['package_name'] = context['plugin_slug'].replace('-', '_')
65+
context["plugin_slug"] = context["plugin_title"].replace(" ", "-").lower()
66+
context["package_name"] = context["plugin_slug"].replace("-", "_")
6367

6468
# Convert the package slug to a distribution name
6569
# e.g. 'custom-plugin' -> 'inventree-custom-plugin'
66-
pkg = context['plugin_slug']
70+
pkg = context["plugin_slug"]
6771

68-
if not pkg.startswith('inventree-'):
69-
pkg = f'inventree-{pkg}'
72+
if not pkg.startswith("inventree-"):
73+
pkg = f"inventree-{pkg}"
7074

71-
context['distribution_name'] = pkg
75+
context["distribution_name"] = pkg
7276

7377
success(
7478
f"Generating plugin '{context['package_name']}' - {context['plugin_description']}"
7579
)
7680

77-
info('Enter author information:')
81+
info("Enter author information:")
7882

79-
context['author_name'] = (
83+
context["author_name"] = (
8084
questionary.text(
81-
'Author name',
82-
default=context['author_name'],
85+
"Author name",
86+
default=context["author_name"],
8387
validate=validators.NotEmptyValidator,
8488
)
8589
.ask()
8690
.strip()
8791
)
8892

89-
context['author_email'] = (
90-
questionary.text('Author email', default=context['author_email']).ask().strip()
93+
context["author_email"] = (
94+
questionary.text("Author email", default=context["author_email"]).ask().strip()
9195
)
9296

93-
context['project_url'] = (
94-
questionary.text('Project URL', default=context['project_url']).ask().strip()
97+
context["project_url"] = (
98+
questionary.text("Project URL", default=context["project_url"]).ask().strip()
9599
)
96100

97101
# Extract license information
98102
available_licences = list(license_pkg.iter())
99103
license_keys = [lic.id for lic in available_licences]
100104

101-
context['license_key'] = questionary.select(
102-
'Select a license', default='MIT', choices=license_keys
105+
context["license_key"] = questionary.select(
106+
"Select a license", default="MIT", choices=license_keys
103107
).ask()
104108

105-
context['license_text'] = license_pkg.find(context['license_key']).render(
106-
name=context['author_name'], email=context['author_email']
109+
context["license_text"] = license_pkg.find(context["license_key"]).render(
110+
name=context["author_name"], email=context["author_email"]
107111
)
108112

109113
# Plugin structure information
110-
info('Enter plugin structure information:')
114+
info("Enter plugin structure information:")
111115

112116
plugin_mixins = mixins.get_mixins()
113117

114-
context['plugin_mixins'] = {'mixin_list': plugin_mixins}
118+
context["plugin_mixins"] = {"mixin_list": plugin_mixins}
115119

116120
# If we want to add frontend code support
117-
if 'UserInterfaceMixin' in plugin_mixins:
118-
context['frontend'] = {
119-
'enabled': True,
120-
'features': frontend.select_features(),
121-
'translation': frontend.enable_translation(),
122-
}
123-
else:
124-
context['frontend'] = {'enabled': False, 'features': frontend.no_features()}
121+
frontend_enabled = "UserInterfaceMixin" in plugin_mixins
122+
123+
context["frontend"] = frontend.define_frontend(frontend_enabled)
125124

126125
# Devops information
127-
info('Enter plugin devops support information:')
126+
info("Enter plugin devops support information:")
128127

129-
git_support = context['git_support'] = questionary.confirm(
130-
'Enable Git integration?', default=True
128+
git_support = context["git_support"] = questionary.confirm(
129+
"Enable Git integration?", default=True
131130
).ask()
132131

133-
context['ci_support'] = devops.get_devops_mode() if git_support else 'None'
132+
context["ci_support"] = devops.get_devops_mode() if git_support else "None"
134133

135134
return context
136135

137136

138137
def cleanup(plugin_dir: str, context: dict) -> None:
139138
"""Cleanup generated files after cookiecutter runs."""
140-
info('Cleaning up generated files...')
139+
info("Cleaning up generated files...")
141140

142-
devops.cleanup_devops_files(context['ci_support'], plugin_dir)
141+
devops.cleanup_devops_files(context["ci_support"], plugin_dir)
143142

144143
# Remove frontend code entirely if not enabled
145-
if context['frontend']['enabled']:
144+
if context["frontend"]["enabled"]:
146145
frontend.update_frontend(plugin_dir, context)
147146
else:
148147
frontend.remove_frontend(plugin_dir)
149148

150149
# Cleanup mixins
151150
mixins.cleanup_mixins(plugin_dir, context)
152151

153-
if context['git_support']:
152+
if context["git_support"]:
154153
devops.git_init(plugin_dir)
155154

156155

157156
def main():
158157
"""Run plugin scaffolding."""
159-
parser = argparse.ArgumentParser(description='InvenTree Plugin Creator Tool')
158+
parser = argparse.ArgumentParser(description="InvenTree Plugin Creator Tool")
160159
parser.add_argument(
161-
'--default',
162-
action='store_true',
163-
help='Use default values for all prompts (non-interactive mode)',
160+
"--default",
161+
action="store_true",
162+
help="Use default values for all prompts (non-interactive mode)",
164163
)
165164
parser.add_argument(
166-
'--output', action='store', help='Specify output directory', default='.'
165+
"--output", action="store", help="Specify output directory", default="."
167166
)
168167
parser.add_argument(
169-
'--version', action='version', version=f'%(prog)s {PLUGIN_CREATOR_VERSION}'
168+
"--version", action="version", version=f"%(prog)s {PLUGIN_CREATOR_VERSION}"
170169
)
171170

172171
args = parser.parse_args()
173172

174-
info('InvenTree Plugin Creator Tool')
173+
info("InvenTree Plugin Creator Tool")
175174

176175
context = default_values()
177176
context.update(config.load_config())
178177

179178
# Set version information
180-
context['plugin_creator_version'] = PLUGIN_CREATOR_VERSION
179+
context["plugin_creator_version"] = PLUGIN_CREATOR_VERSION
181180

182181
if args.default:
183-
info('- Using default values for all prompts')
182+
info("- Using default values for all prompts")
184183
else:
185184
context = gather_info(context)
186185

187-
src_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'template')
186+
src_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "template")
188187

189188
output_dir = os.path.abspath(args.output)
190-
plugin_dir = os.path.join(output_dir, context['plugin_name'])
189+
plugin_dir = os.path.join(output_dir, context["plugin_name"])
191190

192191
# Save the user config
193192
config.save_config(context)
194193

195-
info('- output:', plugin_dir)
194+
info("- output:", plugin_dir)
196195

197196
# Run cookiecutter template
198197
cookiecutter(
@@ -209,5 +208,5 @@ def main():
209208
success(f"Plugin created -> '{plugin_dir}'")
210209

211210

212-
if __name__ == '__main__':
211+
if __name__ == "__main__":
213212
main()

plugin_creator/frontend.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@
77
from .helpers import remove_file, remove_dir
88

99

10+
# Minimum version requirements for core frontend libraries
11+
MIN_REACT_VERSION = "19.1.1"
12+
MIN_MANTINE_VERSION = "7.16.0"
13+
14+
1015
def frontend_features() -> dict:
1116
"""Provide a list of frontend features to enable."""
1217

@@ -62,6 +67,30 @@ def remove_frontend(plugin_dir: str) -> None:
6267
remove_dir(plugin_dir, "frontend")
6368

6469

70+
def define_frontend(enabled: bool, defaults: bool = False) -> dict:
71+
"""Define the frontend code options for the plugin."""
72+
73+
frontend = {
74+
"react_version": MIN_REACT_VERSION,
75+
"mantine_version": MIN_MANTINE_VERSION,
76+
}
77+
78+
if enabled:
79+
frontend.update({
80+
"enabled": True,
81+
"features": all_features() if defaults else select_features(),
82+
"translation": True if defaults else enable_translation(),
83+
})
84+
else:
85+
frontend.update({
86+
"enabled": False,
87+
"translation": False,
88+
"features": no_features(),
89+
})
90+
91+
return frontend
92+
93+
6594
def update_frontend(plugin_dir: str, context: dict) -> None:
6695
"""Update the frontend code for the plugin."""
6796

plugin_creator/template/cookiecutter.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232
"frontend": {
3333
"enabled": true,
3434
"translation": true,
35+
"react_version": "0.0.0",
36+
"mantine_version": "0.0.0",
3537
"features": {
3638
"dashboard": true,
3739
"panel": true,

plugin_creator/template/{{ cookiecutter.plugin_name }}/frontend/package.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,13 @@
1515
"dev": "vite --config vite.dev.config.ts --host"
1616
},
1717
"dependencies": {
18-
"@inventreedb/ui": "latest"
18+
"@inventreedb/ui": "latest",
19+
"react": ">= {{ cookiecutter.frontend.react_version }}",
20+
"react-dom": ">= {{ cookiecutter.frontend.react_version }}",
21+
"@mantine/core": ">= {{ cookiecutter.frontend.mantine_version }}",
22+
"@mantine/hooks": ">= {{ cookiecutter.frontend.mantine_version }}",
23+
"@mantine/modals": ">= {{ cookiecutter.frontend.mantine_version }}",
24+
"@mantine/notifications": ">= {{ cookiecutter.frontend.mantine_version }}"
1925
},
2026
"peerDependencies": {},
2127
"devDependencies": {
@@ -29,7 +35,7 @@
2935
{%- endif %}
3036
"@types/react": "latest",
3137
"@types/react-dom": "latest",
32-
"@vitejs/plugin-react": "^4.3.4",
38+
"@vitejs/plugin-react": "^4.7.0",
3339
"globals": "^15.14.0",
3440
"typescript": "~5.6.2",
3541
"vite": "^6.0.5",

0 commit comments

Comments
 (0)