@fgv/ts-res-browser 5.0.0-2 → 5.0.0-21
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.
- package/cli.js +132 -21
- package/dist/bundle.js +1 -1
- package/dist/bundle.js.LICENSE.txt +11 -1
- package/package.json +42 -36
- package/.rush/temp/587277bfc395406ad444e989b6c309b9698f534c.tar.log +0 -15
- package/.rush/temp/chunked-rush-logs/ts-res-browser.build.chunks.jsonl +0 -35
- package/.rush/temp/operation/build/all.log +0 -35
- package/.rush/temp/operation/build/log-chunks.jsonl +0 -35
- package/.rush/temp/operation/build/state.json +0 -3
- package/.rush/temp/shrinkwrap-deps.json +0 -1225
- package/TS_RES_BROWSER_PLAN.md +0 -689
- package/babel.config.js +0 -17
- package/config/jest.config.json +0 -13
- package/config/rig.json +0 -16
- package/postcss.config.js +0 -3
- package/public/index.html +0 -15
- package/rush-logs/ts-res-browser.build.cache.log +0 -3
- package/rush-logs/ts-res-browser.build.log +0 -35
- package/src/App.tsx +0 -274
- package/src/cli.ts +0 -44
- package/src/components/common/FileImporter.tsx +0 -143
- package/src/components/common/NavigationWarningModal.tsx +0 -62
- package/src/components/layout/AppLayout.tsx +0 -46
- package/src/components/layout/Header.tsx +0 -22
- package/src/components/layout/MessagesWindow.tsx +0 -108
- package/src/components/layout/Sidebar.tsx +0 -99
- package/src/components/tools/CompiledBrowser.tsx +0 -949
- package/src/components/tools/ConfigurationTool.tsx +0 -1405
- package/src/components/tools/FilterTool.tsx +0 -1114
- package/src/components/tools/ImportTool.tsx +0 -249
- package/src/components/tools/ResolutionViewer.tsx +0 -1672
- package/src/components/tools/SourceBrowser.tsx +0 -496
- package/src/components/tools/ZipLoader.tsx +0 -302
- package/src/hooks/useAppState.ts +0 -111
- package/src/hooks/useFileImport.ts +0 -86
- package/src/hooks/useNavigationWarning.ts +0 -67
- package/src/hooks/useResourceManager.ts +0 -295
- package/src/hooks/useUrlParams.ts +0 -56
- package/src/index.css +0 -38
- package/src/main.tsx +0 -16
- package/src/types/app.ts +0 -70
- package/src/types/fileSystemAccess.d.ts +0 -94
- package/src/utils/browserFileTreeAccessors.ts +0 -245
- package/src/utils/fileImport.ts +0 -336
- package/src/utils/fileTreeConverter.ts +0 -160
- package/src/utils/filterResources.ts +0 -677
- package/src/utils/tsResIntegration.ts +0 -467
- package/src/utils/urlParams.ts +0 -238
- package/src/utils/zip/browserZipFileTreeAccessors.ts +0 -385
- package/tailwind.config.js +0 -21
- package/test-data/README.md +0 -184
- package/test-data/config-variations/README.md +0 -64
- package/test-data/config-variations/composition-terminology.json +0 -112
- package/test-data/config-variations/enterprise-complex.json +0 -129
- package/test-data/config-variations/gaming-app.json +0 -87
- package/test-data/config-variations/high-priority-language.json +0 -65
- package/test-data/config-variations/minimal-basic.json +0 -37
- package/test-data/config-variations/qualifier-default-values.json +0 -71
- package/test-data/config-variations/territory-first.json +0 -68
- package/test-data/config-variations/territory-hierarchy-test.json +0 -31
- package/test-data/config-variations/territory-hierarchy-unconstrained.json +0 -32
- package/test-data/default-matching-test/greeting.res.json +0 -83
- package/test-data/default-matching-test/only-defaults.res.json +0 -48
- package/test-data/sample-project/package.json +0 -27
- package/test-data/sample-project/src/resources/app-config.json +0 -27
- package/test-data/sample-project/src/resources/app.json +0 -177
- package/test-data/sample-project/src/resources/config/app.env=development.json +0 -21
- package/test-data/sample-project/src/resources/config/app.json +0 -21
- package/test-data/sample-project/src/resources/config/app.platform=mobile.json +0 -23
- package/test-data/sample-project/src/resources/feature-flags.json +0 -23
- package/test-data/sample-project/src/resources/home=CA/common.json +0 -16
- package/test-data/sample-project/src/resources/images/density=hdpi.json +0 -29
- package/test-data/sample-project/src/resources/images/home.json +0 -29
- package/test-data/sample-project/src/resources/images/logout.json +0 -14
- package/test-data/sample-project/src/resources/images/settings.json +0 -14
- package/test-data/sample-project/src/resources/images/ui-icons.json +0 -29
- package/test-data/sample-project/src/resources/images/user.density=hdpi.json +0 -14
- package/test-data/sample-project/src/resources/images/user.json +0 -14
- package/test-data/sample-project/src/resources/lang=en-US/common.json +0 -15
- package/test-data/sample-project/src/resources/language=en-CA/ui-terms.json +0 -19
- package/test-data/sample-project/src/resources/language=en-GB/ui-terms.json +0 -30
- package/test-data/sample-project/src/resources/language=fr-CA/ui-terms.json +0 -25
- package/test-data/sample-project/src/resources/language=nl-BE/ui-terms.json +0 -17
- package/test-data/sample-project/src/resources/region=europe/feature-flags.json +0 -17
- package/test-data/sample-project/src/resources/region=north-america/feature-flags.json +0 -18
- package/test-data/sample-project/src/resources/strings/dashboard.home=CA,language=fr.json +0 -20
- package/test-data/sample-project/src/resources/strings/dashboard.json +0 -18
- package/test-data/sample-project/src/resources/strings/dashboard.role=admin.json +0 -23
- package/test-data/sample-project/src/resources/strings/dashboard.role=user.json +0 -21
- package/test-data/sample-project/src/resources/strings/language=en-US.json +0 -16
- package/test-data/sample-project/src/resources/strings.json +0 -78
- package/test-data/sample-project/src/resources/territory=BE/app-config.json +0 -19
- package/test-data/sample-project/src/resources/territory=CA/app-config.json +0 -21
- package/test-data/sample-project/src/resources/territory=GB/app-config.json +0 -25
- package/test-data/sample-project/src/resources/territory=NL/app-config.json +0 -25
- package/test-data/sample-project/src/resources/ui-terms.json +0 -96
- package/test-data/sample-project/src/resources-config.json +0 -111
- package/tsconfig.json +0 -27
- package/webpack.config.js +0 -60
package/babel.config.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
presets: [
|
|
3
|
-
[
|
|
4
|
-
'@babel/preset-env',
|
|
5
|
-
{
|
|
6
|
-
targets: {
|
|
7
|
-
browsers: ['last 2 versions', 'not dead']
|
|
8
|
-
},
|
|
9
|
-
useBuiltIns: 'usage',
|
|
10
|
-
corejs: 3
|
|
11
|
-
}
|
|
12
|
-
],
|
|
13
|
-
'@babel/preset-react',
|
|
14
|
-
'@babel/preset-typescript'
|
|
15
|
-
],
|
|
16
|
-
plugins: []
|
|
17
|
-
};
|
package/config/jest.config.json
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"preset": "ts-jest",
|
|
3
|
-
"testEnvironment": "jsdom",
|
|
4
|
-
"roots": ["<rootDir>/src"],
|
|
5
|
-
"testMatch": ["**/__tests__/**/*.ts?(x)", "**/?(*.)+(spec|test).ts?(x)"],
|
|
6
|
-
"transform": {
|
|
7
|
-
"^.+\\.(ts|tsx)$": "ts-jest"
|
|
8
|
-
},
|
|
9
|
-
"moduleNameMapping": {
|
|
10
|
-
"^@/(.*)$": "<rootDir>/src/$1"
|
|
11
|
-
},
|
|
12
|
-
"setupFilesAfterEnv": ["<rootDir>/src/setupTests.ts"]
|
|
13
|
-
}
|
package/config/rig.json
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
// The "rig.json" file directs tools to look for their config files in an external package.
|
|
2
|
-
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
|
|
3
|
-
{
|
|
4
|
-
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
|
|
5
|
-
/**
|
|
6
|
-
* (Required) The name of the rig package to inherit from.
|
|
7
|
-
* It should be an NPM package name with the "-rig" suffix.
|
|
8
|
-
*/
|
|
9
|
-
"rigPackageName": "@rushstack/heft-web-rig",
|
|
10
|
-
/**
|
|
11
|
-
* (Optional) Selects a config profile from the rig package. The name must consist of
|
|
12
|
-
* lowercase alphanumeric words separated by hyphens, for example "sample-profile".
|
|
13
|
-
* If omitted, then the "default" profile will be used."
|
|
14
|
-
*/
|
|
15
|
-
"rigProfile": "app"
|
|
16
|
-
}
|
package/postcss.config.js
DELETED
package/public/index.html
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<link rel="icon" href="/favicon.ico" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
-
<meta name="theme-color" content="#000000" />
|
|
8
|
-
<meta name="description" content="Visual browser tool for ts-res resources" />
|
|
9
|
-
<title>TS-RES Browser</title>
|
|
10
|
-
</head>
|
|
11
|
-
<body>
|
|
12
|
-
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
13
|
-
<div id="root"></div>
|
|
14
|
-
</body>
|
|
15
|
-
</html>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
Invoking: webpack --mode production
|
|
2
|
-
asset bundle.js 2.41 MiB [emitted] [minimized] [big] (name: main) 1 related asset
|
|
3
|
-
asset index.html 478 bytes [emitted]
|
|
4
|
-
orphan modules 678 KiB [orphan] 353 modules
|
|
5
|
-
runtime modules 1.02 KiB 6 modules
|
|
6
|
-
modules by path ../../common/temp/node_modules/.pnpm/ 2.38 MiB 841 modules
|
|
7
|
-
modules by path ../../libraries/ 2.24 MiB
|
|
8
|
-
javascript modules 1.41 MiB 314 modules
|
|
9
|
-
json modules 849 KiB 4 modules
|
|
10
|
-
optional modules 60 bytes [optional]
|
|
11
|
-
buffer (ignored) 15 bytes [optional] [built] [code generated]
|
|
12
|
-
crypto (ignored) 15 bytes [optional] [built] [code generated]
|
|
13
|
-
buffer (ignored) 15 bytes [optional] [built] [code generated]
|
|
14
|
-
vm (ignored) 15 bytes [optional] [built] [code generated]
|
|
15
|
-
modules by path ./src/ 406 KiB
|
|
16
|
-
./src/main.tsx + 54 modules 370 KiB [built] [code generated]
|
|
17
|
-
../../common/temp/node_modules/.pnpm/css-loader@7.1.2_webpack@5.100.1/node_modules/css-loader/dist/cjs.js!../../common/temp/node_modules/.pnpm/postcss-loader@8.1.1_postcss@8.5.6_typescript@5.8.3_webpack@5.100.1/node_modules/postcss-loader/dist/cjs.js!./src/index.css 35.7 KiB [built] [code generated]
|
|
18
|
-
+ 15 modules
|
|
19
|
-
|
|
20
|
-
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
|
|
21
|
-
This can impact web performance.
|
|
22
|
-
Assets:
|
|
23
|
-
bundle.js (2.41 MiB)
|
|
24
|
-
|
|
25
|
-
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
|
|
26
|
-
Entrypoints:
|
|
27
|
-
main (2.41 MiB)
|
|
28
|
-
bundle.js
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
WARNING in webpack performance recommendations:
|
|
32
|
-
You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
|
|
33
|
-
For more info visit https://webpack.js.org/guides/code-splitting/
|
|
34
|
-
|
|
35
|
-
webpack 5.100.1 compiled with 3 warnings in 21598 ms
|
package/src/App.tsx
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import React, { useCallback, useEffect } from 'react';
|
|
2
|
-
import AppLayout from './components/layout/AppLayout';
|
|
3
|
-
import ImportTool from './components/tools/ImportTool';
|
|
4
|
-
import SourceBrowser from './components/tools/SourceBrowser';
|
|
5
|
-
import FilterTool from './components/tools/FilterTool';
|
|
6
|
-
import CompiledBrowser from './components/tools/CompiledBrowser';
|
|
7
|
-
import ResolutionViewer from './components/tools/ResolutionViewer';
|
|
8
|
-
import ConfigurationTool from './components/tools/ConfigurationTool';
|
|
9
|
-
import ZipLoader from './components/tools/ZipLoader';
|
|
10
|
-
import NavigationWarningModal from './components/common/NavigationWarningModal';
|
|
11
|
-
import { useAppState } from './hooks/useAppState';
|
|
12
|
-
import { useFileImport } from './hooks/useFileImport';
|
|
13
|
-
import { useResourceManager } from './hooks/useResourceManager';
|
|
14
|
-
import { useNavigationWarning } from './hooks/useNavigationWarning';
|
|
15
|
-
import { useUrlParams } from './hooks/useUrlParams';
|
|
16
|
-
import { FilterResult } from './utils/filterResources';
|
|
17
|
-
import { parseContextFilter } from './utils/urlParams';
|
|
18
|
-
import { Tool } from './types/app';
|
|
19
|
-
import * as TsRes from '@fgv/ts-res';
|
|
20
|
-
|
|
21
|
-
const App: React.FC = () => {
|
|
22
|
-
const { state, actions } = useAppState();
|
|
23
|
-
const fileImport = useFileImport();
|
|
24
|
-
const resourceManager = useResourceManager();
|
|
25
|
-
const navigationWarning = useNavigationWarning();
|
|
26
|
-
const { urlParams, hasUrlParams } = useUrlParams();
|
|
27
|
-
|
|
28
|
-
// State to share filter result between components
|
|
29
|
-
const [filterResult, setFilterResult] = React.useState<FilterResult | null>(null);
|
|
30
|
-
|
|
31
|
-
// Ref to store the configuration tool's save handler
|
|
32
|
-
const configSaveHandlerRef = React.useRef<(() => void) | null>(null);
|
|
33
|
-
|
|
34
|
-
// Ref to track if we've already initialized from URL parameters
|
|
35
|
-
const initializedFromUrlRef = React.useRef(false);
|
|
36
|
-
|
|
37
|
-
// Initialize app state from URL parameters (only run once)
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
if (hasUrlParams && !initializedFromUrlRef.current) {
|
|
40
|
-
initializedFromUrlRef.current = true;
|
|
41
|
-
|
|
42
|
-
// Load and apply configuration if provided
|
|
43
|
-
if (urlParams.config) {
|
|
44
|
-
const loadConfiguration = async () => {
|
|
45
|
-
try {
|
|
46
|
-
// Check if it's a predefined configuration name
|
|
47
|
-
const predefinedNames: TsRes.Config.PredefinedSystemConfiguration[] = [
|
|
48
|
-
'default',
|
|
49
|
-
'language-priority',
|
|
50
|
-
'territory-priority',
|
|
51
|
-
'extended-example'
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
if (predefinedNames.includes(urlParams.config as TsRes.Config.PredefinedSystemConfiguration)) {
|
|
55
|
-
// Load predefined configuration
|
|
56
|
-
const configResult = TsRes.Config.getPredefinedDeclaration(
|
|
57
|
-
urlParams.config as TsRes.Config.PredefinedSystemConfiguration
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
if (configResult.isSuccess()) {
|
|
61
|
-
// Store the declaration directly, not the SystemConfiguration instance
|
|
62
|
-
resourceManager.actions.applyConfiguration(configResult.value);
|
|
63
|
-
actions.addMessage('success', `Loaded predefined configuration: ${urlParams.config}`);
|
|
64
|
-
} else {
|
|
65
|
-
actions.addMessage(
|
|
66
|
-
'error',
|
|
67
|
-
`Failed to load predefined configuration '${urlParams.config}': ${configResult.message}`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
// It might be a file path - show a message for now
|
|
72
|
-
actions.addMessage(
|
|
73
|
-
'info',
|
|
74
|
-
`Configuration file specified: ${urlParams.config} (file loading not yet supported)`
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
} catch (error) {
|
|
78
|
-
actions.addMessage('error', `Error loading configuration: ${error}`);
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
loadConfiguration();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Apply context filter if provided
|
|
86
|
-
if (urlParams.contextFilter) {
|
|
87
|
-
try {
|
|
88
|
-
const contextObj = parseContextFilter(urlParams.contextFilter);
|
|
89
|
-
actions.updateFilterValues(contextObj);
|
|
90
|
-
actions.updateFilterEnabled(true);
|
|
91
|
-
actions.applyFilterValues();
|
|
92
|
-
actions.addMessage('info', `Applied context filter from URL: ${urlParams.contextFilter}`);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
actions.addMessage('error', `Invalid context filter in URL: ${urlParams.contextFilter}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Apply reduceQualifiers setting
|
|
99
|
-
if (urlParams.reduceQualifiers) {
|
|
100
|
-
actions.updateReduceQualifiers(true);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Handle ZIP loading
|
|
104
|
-
if (urlParams.loadZip) {
|
|
105
|
-
actions.setActiveTool('zip-loader');
|
|
106
|
-
actions.addMessage('info', 'ZIP archive ready to load');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// Show appropriate messages for other parameters
|
|
110
|
-
if (urlParams.input) {
|
|
111
|
-
actions.addMessage('info', `Ready to load resource file: ${urlParams.input}`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (urlParams.resourceTypes) {
|
|
115
|
-
actions.addMessage('info', `Resource types filter: ${urlParams.resourceTypes}`);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (urlParams.maxDistance !== undefined) {
|
|
119
|
-
actions.addMessage('info', `Language matching distance: ${urlParams.maxDistance}`);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (urlParams.interactive) {
|
|
123
|
-
actions.addMessage('info', 'Launched in interactive mode - sample data will be loaded');
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Navigate to appropriate tool based on URL params
|
|
127
|
-
if (urlParams.input) {
|
|
128
|
-
// If input is specified, start with import tool
|
|
129
|
-
actions.setSelectedTool('import');
|
|
130
|
-
} else if (urlParams.interactive) {
|
|
131
|
-
// If interactive mode, might want to go straight to source browser with sample data
|
|
132
|
-
actions.setSelectedTool('source');
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}, [hasUrlParams]); // Remove urlParams and actions to prevent re-runs
|
|
136
|
-
|
|
137
|
-
// Handle navigation with unsaved changes check
|
|
138
|
-
const handleToolSelect = useCallback(
|
|
139
|
-
(tool: Tool) => {
|
|
140
|
-
// If we're trying to navigate away from configuration and have unsaved changes
|
|
141
|
-
if (state.selectedTool === 'configuration' && navigationWarning.state.hasUnsavedChanges) {
|
|
142
|
-
navigationWarning.actions.showWarning(tool);
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Otherwise, navigate normally
|
|
147
|
-
actions.setSelectedTool(tool);
|
|
148
|
-
},
|
|
149
|
-
[state.selectedTool, navigationWarning, actions]
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
// Handle save and continue from navigation warning
|
|
153
|
-
const handleSaveAndContinue = useCallback(() => {
|
|
154
|
-
// Call the configuration tool's save handler if available
|
|
155
|
-
if (configSaveHandlerRef.current) {
|
|
156
|
-
configSaveHandlerRef.current();
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const pendingTool = navigationWarning.actions.confirmNavigation();
|
|
160
|
-
if (pendingTool) {
|
|
161
|
-
actions.setSelectedTool(pendingTool);
|
|
162
|
-
}
|
|
163
|
-
}, [navigationWarning, actions]);
|
|
164
|
-
|
|
165
|
-
// Handle discard changes and continue
|
|
166
|
-
const handleDiscardAndContinue = useCallback(() => {
|
|
167
|
-
const pendingTool = navigationWarning.actions.confirmNavigation();
|
|
168
|
-
if (pendingTool) {
|
|
169
|
-
actions.setSelectedTool(pendingTool);
|
|
170
|
-
}
|
|
171
|
-
}, [navigationWarning, actions]);
|
|
172
|
-
|
|
173
|
-
const renderTool = () => {
|
|
174
|
-
switch (state.selectedTool) {
|
|
175
|
-
case 'import':
|
|
176
|
-
return (
|
|
177
|
-
<ImportTool
|
|
178
|
-
onMessage={actions.addMessage}
|
|
179
|
-
fileImport={fileImport}
|
|
180
|
-
resourceManager={resourceManager}
|
|
181
|
-
/>
|
|
182
|
-
);
|
|
183
|
-
case 'source':
|
|
184
|
-
return <SourceBrowser onMessage={actions.addMessage} resourceManager={resourceManager} />;
|
|
185
|
-
case 'filter':
|
|
186
|
-
return (
|
|
187
|
-
<FilterTool
|
|
188
|
-
onMessage={actions.addMessage}
|
|
189
|
-
resourceManager={resourceManager}
|
|
190
|
-
filterState={state.filterState}
|
|
191
|
-
filterActions={{
|
|
192
|
-
updateFilterEnabled: actions.updateFilterEnabled,
|
|
193
|
-
updateFilterValues: actions.updateFilterValues,
|
|
194
|
-
applyFilterValues: actions.applyFilterValues,
|
|
195
|
-
resetFilterValues: actions.resetFilterValues,
|
|
196
|
-
updateReduceQualifiers: actions.updateReduceQualifiers
|
|
197
|
-
}}
|
|
198
|
-
onFilterResult={setFilterResult}
|
|
199
|
-
/>
|
|
200
|
-
);
|
|
201
|
-
case 'compiled':
|
|
202
|
-
return (
|
|
203
|
-
<CompiledBrowser
|
|
204
|
-
onMessage={actions.addMessage}
|
|
205
|
-
resourceManager={resourceManager}
|
|
206
|
-
filterState={state.filterState}
|
|
207
|
-
filterResult={filterResult}
|
|
208
|
-
/>
|
|
209
|
-
);
|
|
210
|
-
case 'resolution':
|
|
211
|
-
return (
|
|
212
|
-
<ResolutionViewer
|
|
213
|
-
onMessage={actions.addMessage}
|
|
214
|
-
resourceManager={resourceManager}
|
|
215
|
-
filterState={state.filterState}
|
|
216
|
-
filterResult={filterResult}
|
|
217
|
-
/>
|
|
218
|
-
);
|
|
219
|
-
case 'configuration':
|
|
220
|
-
return (
|
|
221
|
-
<ConfigurationTool
|
|
222
|
-
onMessage={actions.addMessage}
|
|
223
|
-
resourceManager={resourceManager}
|
|
224
|
-
onUnsavedChanges={navigationWarning.actions.setHasUnsavedChanges}
|
|
225
|
-
onSaveHandlerRef={configSaveHandlerRef}
|
|
226
|
-
/>
|
|
227
|
-
);
|
|
228
|
-
case 'zip-loader':
|
|
229
|
-
return (
|
|
230
|
-
<ZipLoader
|
|
231
|
-
onMessage={actions.addMessage}
|
|
232
|
-
resourceManager={resourceManager}
|
|
233
|
-
zipFile={urlParams.zipFile}
|
|
234
|
-
zipPath={urlParams.zipPath}
|
|
235
|
-
onLoadComplete={() => {
|
|
236
|
-
// Switch to source browser after successful load
|
|
237
|
-
actions.setSelectedTool('source');
|
|
238
|
-
}}
|
|
239
|
-
/>
|
|
240
|
-
);
|
|
241
|
-
default:
|
|
242
|
-
return (
|
|
243
|
-
<ImportTool
|
|
244
|
-
onMessage={actions.addMessage}
|
|
245
|
-
fileImport={fileImport}
|
|
246
|
-
resourceManager={resourceManager}
|
|
247
|
-
/>
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
return (
|
|
253
|
-
<>
|
|
254
|
-
<AppLayout
|
|
255
|
-
selectedTool={state.selectedTool}
|
|
256
|
-
onToolSelect={handleToolSelect}
|
|
257
|
-
messages={state.messages}
|
|
258
|
-
onClearMessages={actions.clearMessages}
|
|
259
|
-
>
|
|
260
|
-
{renderTool()}
|
|
261
|
-
</AppLayout>
|
|
262
|
-
|
|
263
|
-
<NavigationWarningModal
|
|
264
|
-
isOpen={navigationWarning.state.isWarningOpen}
|
|
265
|
-
onCancel={navigationWarning.actions.hideWarning}
|
|
266
|
-
onConfirm={handleDiscardAndContinue}
|
|
267
|
-
onSave={handleSaveAndContinue}
|
|
268
|
-
hasUnsavedChanges={navigationWarning.state.hasUnsavedChanges}
|
|
269
|
-
/>
|
|
270
|
-
</>
|
|
271
|
-
);
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
export default App;
|
package/src/cli.ts
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { exec } from 'child_process';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
|
|
6
|
-
const command = process.argv[2];
|
|
7
|
-
|
|
8
|
-
switch (command) {
|
|
9
|
-
case 'dev':
|
|
10
|
-
console.log('Starting TS-RES Browser development server...');
|
|
11
|
-
exec('npm run dev', { cwd: __dirname }, (error, stdout, stderr) => {
|
|
12
|
-
if (error) {
|
|
13
|
-
console.error(`Error: ${error}`);
|
|
14
|
-
return;
|
|
15
|
-
}
|
|
16
|
-
console.log(stdout);
|
|
17
|
-
if (stderr) console.error(stderr);
|
|
18
|
-
});
|
|
19
|
-
break;
|
|
20
|
-
|
|
21
|
-
case 'build':
|
|
22
|
-
console.log('Building TS-RES Browser...');
|
|
23
|
-
exec('npm run build', { cwd: __dirname }, (error, stdout, stderr) => {
|
|
24
|
-
if (error) {
|
|
25
|
-
console.error(`Error: ${error}`);
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
console.log(stdout);
|
|
29
|
-
if (stderr) console.error(stderr);
|
|
30
|
-
});
|
|
31
|
-
break;
|
|
32
|
-
|
|
33
|
-
default:
|
|
34
|
-
console.log('TS-RES Browser CLI');
|
|
35
|
-
console.log('');
|
|
36
|
-
console.log('Usage:');
|
|
37
|
-
console.log(' ts-res-browser dev - Start development server');
|
|
38
|
-
console.log(' ts-res-browser build - Build for production');
|
|
39
|
-
console.log('');
|
|
40
|
-
console.log('For development, you can also use:');
|
|
41
|
-
console.log(' rushx dev - Start development server');
|
|
42
|
-
console.log(' rushx build - Build for production');
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
import React, { useState, useCallback } from 'react';
|
|
2
|
-
import { FolderOpenIcon, DocumentArrowUpIcon, ExclamationTriangleIcon } from '@heroicons/react/24/outline';
|
|
3
|
-
import {
|
|
4
|
-
fileImporter,
|
|
5
|
-
isFileSystemAccessSupported,
|
|
6
|
-
ImportedDirectory,
|
|
7
|
-
ImportedFile
|
|
8
|
-
} from '../../utils/fileImport';
|
|
9
|
-
import { Result } from '@fgv/ts-utils';
|
|
10
|
-
|
|
11
|
-
interface FileImporterProps {
|
|
12
|
-
onDirectoryImported?: (directory: ImportedDirectory) => void;
|
|
13
|
-
onFilesImported?: (files: ImportedFile[]) => void;
|
|
14
|
-
onError?: (error: string) => void;
|
|
15
|
-
startInDirectory?: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export const FileImporter: React.FC<FileImporterProps> = ({
|
|
19
|
-
onDirectoryImported,
|
|
20
|
-
onFilesImported,
|
|
21
|
-
onError,
|
|
22
|
-
startInDirectory
|
|
23
|
-
}) => {
|
|
24
|
-
const [isLoading, setIsLoading] = useState(false);
|
|
25
|
-
const [importMethod, setImportMethod] = useState<'modern' | 'fallback'>(
|
|
26
|
-
isFileSystemAccessSupported() ? 'modern' : 'fallback'
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
const handleDirectoryImport = useCallback(async () => {
|
|
30
|
-
setIsLoading(true);
|
|
31
|
-
try {
|
|
32
|
-
const result = await fileImporter.pickDirectory({
|
|
33
|
-
startIn: startInDirectory
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
if (result.isSuccess()) {
|
|
37
|
-
onDirectoryImported?.(result.value);
|
|
38
|
-
} else {
|
|
39
|
-
onError?.(result.error);
|
|
40
|
-
}
|
|
41
|
-
} catch (error) {
|
|
42
|
-
onError?.(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
|
-
} finally {
|
|
44
|
-
setIsLoading(false);
|
|
45
|
-
}
|
|
46
|
-
}, [onDirectoryImported, onError, startInDirectory]);
|
|
47
|
-
|
|
48
|
-
const handleFileImport = useCallback(async () => {
|
|
49
|
-
setIsLoading(true);
|
|
50
|
-
try {
|
|
51
|
-
const result = await fileImporter.pickFiles({
|
|
52
|
-
acceptedTypes: ['.json'],
|
|
53
|
-
multiple: true,
|
|
54
|
-
startIn: startInDirectory
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
if (result.isSuccess()) {
|
|
58
|
-
onFilesImported?.(result.value);
|
|
59
|
-
} else {
|
|
60
|
-
onError?.(result.error);
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
63
|
-
onError?.(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);
|
|
64
|
-
} finally {
|
|
65
|
-
setIsLoading(false);
|
|
66
|
-
}
|
|
67
|
-
}, [onFilesImported, onError, startInDirectory]);
|
|
68
|
-
|
|
69
|
-
return (
|
|
70
|
-
<div className="space-y-4">
|
|
71
|
-
{/* Import Method Info */}
|
|
72
|
-
<div className="flex items-center space-x-2 text-sm text-gray-600">
|
|
73
|
-
{importMethod === 'modern' ? (
|
|
74
|
-
<>
|
|
75
|
-
<div className="w-2 h-2 bg-green-500 rounded-full"></div>
|
|
76
|
-
<span>Using modern File System Access API</span>
|
|
77
|
-
</>
|
|
78
|
-
) : (
|
|
79
|
-
<>
|
|
80
|
-
<div className="w-2 h-2 bg-yellow-500 rounded-full"></div>
|
|
81
|
-
<span>Using fallback file input (limited browser support)</span>
|
|
82
|
-
</>
|
|
83
|
-
)}
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
{/* Import Controls */}
|
|
87
|
-
<div className="flex flex-col space-y-3">
|
|
88
|
-
{/* Directory Import */}
|
|
89
|
-
<button
|
|
90
|
-
onClick={handleDirectoryImport}
|
|
91
|
-
disabled={isLoading}
|
|
92
|
-
className="flex items-center justify-center space-x-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
93
|
-
>
|
|
94
|
-
<FolderOpenIcon className="w-5 h-5" />
|
|
95
|
-
<span>{isLoading ? 'Importing...' : 'Import Resource Directory'}</span>
|
|
96
|
-
</button>
|
|
97
|
-
|
|
98
|
-
{/* File Import */}
|
|
99
|
-
<button
|
|
100
|
-
onClick={handleFileImport}
|
|
101
|
-
disabled={isLoading}
|
|
102
|
-
className="flex items-center justify-center space-x-2 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
|
103
|
-
>
|
|
104
|
-
<DocumentArrowUpIcon className="w-5 h-5" />
|
|
105
|
-
<span>{isLoading ? 'Importing...' : 'Import Resource Files'}</span>
|
|
106
|
-
</button>
|
|
107
|
-
</div>
|
|
108
|
-
|
|
109
|
-
{/* Browser Compatibility Warning */}
|
|
110
|
-
{importMethod === 'fallback' && (
|
|
111
|
-
<div className="flex items-start space-x-2 p-3 bg-yellow-50 border border-yellow-200 rounded-lg">
|
|
112
|
-
<ExclamationTriangleIcon className="w-5 h-5 text-yellow-600 mt-0.5 flex-shrink-0" />
|
|
113
|
-
<div className="text-sm text-yellow-800">
|
|
114
|
-
<p className="font-medium">Limited Browser Support</p>
|
|
115
|
-
<p className="mt-1">
|
|
116
|
-
Your browser doesn't support the File System Access API. For the best experience, use Chrome,
|
|
117
|
-
Edge, or another Chromium-based browser.
|
|
118
|
-
</p>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
|
121
|
-
)}
|
|
122
|
-
|
|
123
|
-
{/* Usage Instructions */}
|
|
124
|
-
<div className="text-sm text-gray-600 space-y-2">
|
|
125
|
-
<p className="font-medium">Import Options:</p>
|
|
126
|
-
<ul className="list-disc list-inside space-y-1 ml-2">
|
|
127
|
-
<li>
|
|
128
|
-
<strong>Import Directory:</strong> Select a folder containing ts-res resources
|
|
129
|
-
</li>
|
|
130
|
-
<li>
|
|
131
|
-
<strong>Import Files:</strong> Select individual JSON resource files
|
|
132
|
-
</li>
|
|
133
|
-
</ul>
|
|
134
|
-
<p className="mt-2">
|
|
135
|
-
The importer will automatically detect and parse ts-res resource formats including Resource
|
|
136
|
-
Collections, Resource Trees, and simple JSON files.
|
|
137
|
-
</p>
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
export default FileImporter;
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ExclamationTriangleIcon } from '@heroicons/react/24/outline';
|
|
3
|
-
|
|
4
|
-
interface NavigationWarningModalProps {
|
|
5
|
-
isOpen: boolean;
|
|
6
|
-
onCancel: () => void;
|
|
7
|
-
onConfirm: () => void;
|
|
8
|
-
onSave?: () => void;
|
|
9
|
-
hasUnsavedChanges: boolean;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const NavigationWarningModal: React.FC<NavigationWarningModalProps> = ({
|
|
13
|
-
isOpen,
|
|
14
|
-
onCancel,
|
|
15
|
-
onConfirm,
|
|
16
|
-
onSave,
|
|
17
|
-
hasUnsavedChanges
|
|
18
|
-
}) => {
|
|
19
|
-
if (!isOpen) return null;
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
|
23
|
-
<div className="bg-white rounded-lg shadow-xl p-6 max-w-md w-full mx-4">
|
|
24
|
-
<div className="flex items-center space-x-3 mb-4">
|
|
25
|
-
<ExclamationTriangleIcon className="h-6 w-6 text-amber-500" />
|
|
26
|
-
<h3 className="text-lg font-medium text-gray-900">Unsaved Changes</h3>
|
|
27
|
-
</div>
|
|
28
|
-
|
|
29
|
-
<p className="text-sm text-gray-600 mb-6">
|
|
30
|
-
You have unsaved configuration changes. What would you like to do?
|
|
31
|
-
</p>
|
|
32
|
-
|
|
33
|
-
<div className="flex justify-end space-x-3">
|
|
34
|
-
<button
|
|
35
|
-
onClick={onCancel}
|
|
36
|
-
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
|
37
|
-
>
|
|
38
|
-
Cancel
|
|
39
|
-
</button>
|
|
40
|
-
|
|
41
|
-
<button
|
|
42
|
-
onClick={onConfirm}
|
|
43
|
-
className="px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
|
44
|
-
>
|
|
45
|
-
Discard Changes
|
|
46
|
-
</button>
|
|
47
|
-
|
|
48
|
-
{onSave && (
|
|
49
|
-
<button
|
|
50
|
-
onClick={onSave}
|
|
51
|
-
className="px-4 py-2 text-sm font-medium text-white bg-blue-600 border border-transparent rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
|
52
|
-
>
|
|
53
|
-
Save & Continue
|
|
54
|
-
</button>
|
|
55
|
-
)}
|
|
56
|
-
</div>
|
|
57
|
-
</div>
|
|
58
|
-
</div>
|
|
59
|
-
);
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
export default NavigationWarningModal;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import Header from './Header';
|
|
3
|
-
import Sidebar from './Sidebar';
|
|
4
|
-
import MessagesWindow from './MessagesWindow';
|
|
5
|
-
import { Tool } from '../../types/app';
|
|
6
|
-
|
|
7
|
-
interface AppLayoutProps {
|
|
8
|
-
children: React.ReactNode;
|
|
9
|
-
selectedTool: Tool;
|
|
10
|
-
onToolSelect: (tool: Tool) => void;
|
|
11
|
-
messages: Array<{
|
|
12
|
-
id: string;
|
|
13
|
-
type: 'info' | 'warning' | 'error' | 'success';
|
|
14
|
-
message: string;
|
|
15
|
-
timestamp: Date;
|
|
16
|
-
}>;
|
|
17
|
-
onClearMessages: () => void;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const AppLayout: React.FC<AppLayoutProps> = ({
|
|
21
|
-
children,
|
|
22
|
-
selectedTool,
|
|
23
|
-
onToolSelect,
|
|
24
|
-
messages,
|
|
25
|
-
onClearMessages
|
|
26
|
-
}) => {
|
|
27
|
-
return (
|
|
28
|
-
<div className="min-h-screen bg-gray-50">
|
|
29
|
-
<Header />
|
|
30
|
-
|
|
31
|
-
<div className="flex">
|
|
32
|
-
<Sidebar selectedTool={selectedTool} onToolSelect={onToolSelect} />
|
|
33
|
-
|
|
34
|
-
<main className="flex-1 overflow-hidden">
|
|
35
|
-
<div className="h-full flex flex-col">
|
|
36
|
-
<div className="flex-1 overflow-auto">{children}</div>
|
|
37
|
-
|
|
38
|
-
<MessagesWindow messages={messages} onClearMessages={onClearMessages} />
|
|
39
|
-
</div>
|
|
40
|
-
</main>
|
|
41
|
-
</div>
|
|
42
|
-
</div>
|
|
43
|
-
);
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
export default AppLayout;
|