Skip to content

Commit 3fe5baf

Browse files
authored
Merge branch 'master' into feature/json-editor-settings-clean
2 parents 7236487 + 93c6c02 commit 3fe5baf

File tree

8 files changed

+287
-10
lines changed

8 files changed

+287
-10
lines changed

.github/copilot-instructions.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
Use these instructions for **all** code and answers generated for this repo.
2+
3+
## Project context
4+
5+
- React 18 + TypeScript
6+
- Vite
7+
- Tailwind CSS
8+
- Package manager: Yarn
9+
- Testing: Vitest + React Testing Library
10+
- Lint/format: ESLint + Prettier
11+
12+
## General coding rules
13+
14+
- Prefer **small, focused** changes.
15+
- Follow existing project patterns and naming.
16+
- Avoid `any`. Use proper TypeScript types; use type guards when needed.
17+
- Prefer immutable data (`const`, `readonly`) and functional style where reasonable.
18+
- Use optional chaining (`?.`) and nullish coalescing (`??`) where appropriate.
19+
- Handle errors explicitly (try/catch around risky operations; user-friendly messages if UI-facing).
20+
- Don’t invent files/APIs. If something is unknown, ask a clarifying question.
21+
22+
## TypeScript rules
23+
24+
- Apply the [typescript-instructions.md](./instructions/typescript.instructions.md) guidelines.
25+
- Use TypeScript for all new code (`.ts` / `.tsx`).
26+
- Keep types narrow; avoid over-widening (`string` vs specific unions).
27+
- Keep functions pure when possible; avoid hidden side effects.
28+
29+
## React rules
30+
31+
- Apply the [react-instructions.md](./instructions/react.instructions.md) to all code.
32+
- Add cleanup in effects; avoid memory leaks.
33+
- Accessibility: semantic HTML first, proper labels/ARIA, keyboard support.
34+
35+
## Styling rules
36+
37+
- Use **Tailwind CSS** (avoid inline styles unless truly dynamic).
38+
- Keep Tailwind class order consistent and readable.
39+
40+
## Exports & structure
41+
42+
- Prefer **named exports** for components and utilities (follow existing codebase conventions if a folder differs).
43+
- Keep files organized by feature/domain when adding new code.
44+
45+
## When asked to refactor
46+
47+
- Preserve behavior unless explicitly asked to change it.
48+
- Improve readability first, then performance.
49+
- Avoid broad rewrites; refactor incrementally.
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
description: "ReactJS development standards and best practices"
3+
applyTo: "**/*.jsx, **/*.tsx, **/*.ts"
4+
---
5+
6+
## Project Context
7+
8+
- Latest React version (React 18)
9+
- TypeScript for type safety (when applicable)
10+
- Functional components with hooks as default
11+
- Follow React's official style guide and best practices
12+
- Implement proper component composition and reusability patterns
13+
14+
## Development Standards
15+
16+
### Architecture
17+
18+
- Use functional components with hooks as the primary pattern
19+
- Implement component composition over inheritance
20+
- Organize components by feature or domain for scalability
21+
- Separate presentational and container components clearly
22+
- Use custom hooks for reusable stateful logic
23+
- Implement proper component hierarchies with clear data flow
24+
- Use **functional components + hooks** only. No class components.
25+
- Follow the Rules of Hooks (no conditional hooks; correct deps).
26+
- Use `React.FC` **only when the component uses `children`**; otherwise prefer typed props without `React.FC`.
27+
- Prefer composition over inheritance.
28+
- Use `useMemo`/`useCallback` only when it clearly helps (avoid premature memoization).
29+
30+
### TypeScript Integration
31+
32+
- Use TypeScript interfaces for props, state, and component definitions
33+
- Define proper types for event handlers and refs
34+
- Implement generic components where appropriate
35+
- Use strict mode in `tsconfig.json` for type safety
36+
- Create union types for component variants and states
37+
38+
### Component Design
39+
40+
- Follow the single responsibility principle for components
41+
- Use descriptive and consistent naming conventions
42+
- Implement proper prop validation with TypeScript or PropTypes
43+
- Design components to be testable and reusable
44+
- Keep components small and focused on a single concern
45+
- Use composition patterns (render props, children as functions)
46+
47+
### State Management
48+
49+
- Use `useState` for local component state
50+
- Implement `useReducer` for complex state logic
51+
- Leverage `useContext` for sharing state across component trees
52+
- Consider external state management (Redux Toolkit, Zustand) for complex applications
53+
- Implement proper state normalization and data structures
54+
55+
### Hooks and Effects
56+
57+
- Use `useEffect` with proper dependency arrays to avoid infinite loops
58+
- Implement cleanup functions in effects to prevent memory leaks
59+
- Use `useMemo` and `useCallback` for performance optimization when needed
60+
- Create custom hooks for reusable stateful logic
61+
- Follow the rules of hooks (only call at the top level)
62+
- Use `useRef` for accessing DOM elements and storing mutable values
63+
64+
### Performance Optimization
65+
66+
- Use `React.memo` for component memoization when appropriate
67+
- Implement code splitting with `React.lazy` and `Suspense`
68+
- Optimize bundle size with tree shaking and dynamic imports
69+
- Use `useMemo` and `useCallback` judiciously to prevent unnecessary re-renders
70+
- Implement virtual scrolling for large lists
71+
- Profile components with React DevTools to identify performance bottlenecks
72+
73+
### Data Fetching
74+
75+
- Implement proper loading, error, and success states
76+
- Handle race conditions and request cancellation
77+
- Use optimistic updates for better user experience
78+
- Implement proper caching strategies
79+
- Handle offline scenarios and network errors gracefully
80+
81+
### Error Handling
82+
83+
- Implement Error Boundaries for component-level error handling
84+
- Use proper error states in data fetching
85+
- Implement fallback UI for error scenarios
86+
- Log errors appropriately for debugging
87+
- Handle async errors in effects and event handlers
88+
- Provide meaningful error messages to users
89+
90+
### Forms and Validation
91+
92+
- Use controlled components for form inputs
93+
- Implement proper form validation with libraries like Formik, React Hook Form
94+
- Handle form submission and error states appropriately
95+
- Implement accessibility features for forms (labels, ARIA attributes)
96+
- Use debounced validation for better user experience
97+
- Handle file uploads and complex form scenarios
98+
99+
### Routing
100+
101+
- Use React Router for client-side routing
102+
- Implement nested routes and route protection
103+
- Handle route parameters and query strings properly
104+
- Implement lazy loading for route-based code splitting
105+
- Use proper navigation patterns and back button handling
106+
- Implement breadcrumbs and navigation state management
107+
108+
### Testing
109+
110+
- Write unit tests for components using React Testing Library
111+
- Test component behavior, not implementation details
112+
- Implement integration tests for complex component interactions
113+
- Mock external dependencies and API calls appropriately
114+
- Test accessibility features and keyboard navigation
115+
116+
### Security
117+
118+
- Sanitize user inputs to prevent XSS attacks
119+
- Validate and escape data before rendering
120+
- Use HTTPS for all external API calls
121+
- Implement proper authentication and authorization patterns
122+
- Avoid storing sensitive data in localStorage or sessionStorage
123+
- Use Content Security Policy (CSP) headers
124+
125+
### Accessibility
126+
127+
- Use semantic HTML elements appropriately
128+
- Implement proper ARIA attributes and roles
129+
- Ensure keyboard navigation works for all interactive elements
130+
- Provide alt text for images and descriptive text for icons
131+
- Implement proper color contrast ratios
132+
- Test with screen readers and accessibility tools
133+
134+
## Additional Guidelines
135+
136+
- Follow React's naming conventions (PascalCase for components, camelCase for functions)
137+
- Use meaningful commit messages and maintain clean git history
138+
- Implement proper code splitting and lazy loading strategies
139+
- Document complex components and custom hooks with JSDoc
140+
- Use ESLint and Prettier for consistent code formatting
141+
- Keep dependencies up to date and audit for security vulnerabilities
142+
- Implement proper environment configuration for different deployment stages
143+
- Use React Developer Tools for debugging and performance analysis
144+
145+
## Common Patterns
146+
147+
- Higher-Order Components (HOCs) for cross-cutting concerns
148+
- Render props pattern for component composition
149+
- Compound components for related functionality
150+
- Provider pattern for context-based state sharing
151+
- Container/Presentational component separation
152+
- Custom hooks for reusable logic extraction
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
description: "TypeScript development standards and guidelines"
3+
applyTo: "**/*.ts,**/*.tsx"
4+
---
5+
6+
# TypeScript Guidelines
7+
8+
- Use TypeScript for all new code
9+
- Follow functional programming principles where possible
10+
- Use interfaces for data structures and type definitions
11+
- Prefer immutable data (const, readonly)
12+
- Use optional chaining (?.) and nullish coalescing (??) operators
13+
- Use **interfaces** for data structures/props; use `type` for unions.
14+
15+
## React Guidelines
16+
17+
- Use functional components with hooks
18+
- Follow the React hooks rules (no conditional hooks)
19+
- Use React.FC type for components with children
20+
- Keep components small and focused
21+
- Use CSS modules for component styling

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,4 @@ yarn-debug.log*
3030
yarn-error.log*
3131

3232
.yarn
33-
/doc/tests
33+
/doc

README.md

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ This project aims to make creating W3C Thing Description (TD) instances and Thin
1818
- Exporting the Thing Description / Thing Model from the visual representation into JSON-LD
1919
- Reading/writing exposed properties' values exposed by a proxy (anything that can translate a protocol to HTTP)
2020
- Contributing the Thing Model to a third-party catalog using the Thing Model Catalog (TMC) API.
21-
The detailed API specification is available [here](https://github.com/wot-oss/tmc/blob/main/api/tm-catalog.openapi.yaml).
21+
The detailed **Thing Model Catalog (TMC) OpenAPI specification** is available
22+
[here](https://github.com/wot-oss/tmc/blob/main/api/tm-catalog.openapi.yaml).
2223

2324
## Technologies
2425

@@ -86,14 +87,38 @@ A local repository folder will be created inside the tm-catalog directory
8687

8788
### Send TD feature
8889

89-
To use the **_Send TD_** feature, it is necessary to define in the Settings pop-up the Southbound URL and Northbound URL. The Send TD feature allows you to send your Thing Description to any service following [the WoT TD Directory specification](https://www.w3.org/TR/wot-discovery/#exploration-directory-api-things).
90+
#### Northbound and Southbound URLs
91+
92+
When using the **Send TD** feature, ediTDor communicates with a proxy that exposes
93+
an HTTP interface for interacting with a Thing.
94+
95+
- **Southbound URL**
96+
- Base _Things API collection endpoint_ of the proxy where ediTDor sends the original Thing Description
97+
- ediTDor performs a `POST` to this endpoint; the proxy assigns the Thing/TD identifier
98+
- Used internally by the proxy to reach the underlying Thing using protocol-specific bindings (e.g., Modbus)
99+
100+
- **Northbound URL**
101+
- Base _Things API collection endpoint_ exposed by the proxy after the Thing Description is registered
102+
- ediTDor appends the encoded Thing/TD identifier to this base URL to fetch or interact with the proxied Thing Description
103+
- The proxied TD contains HTTP `href`s that ediTDor can invoke
104+
105+
In practice, ediTDor always interacts with the Thing **through the proxy via the Northbound URL**, while the Southbound URL is used internally by the proxy to communicate with the actual Thing.
106+
To use the **_Send TD_** feature, it is necessary to define in the Settings pop-up the Southbound URL and Northbound URL. The Send TD feature allows you to send your Thing Description to any service following the WoT Discovery _Things API_ specification
107+
(https://www.w3.org/TR/wot-discovery/#exploration-directory-api-things).
90108
Afterwards, if the service proxies the TD, ediTDor can fetch the proxied TD containing HTTP `href`s to interact with the original Thing.
91109

92110
#### Configuration
93111

94112
1. Open the Settings pop-up from the main toolbar
95-
2. Enter your Southbound URL in the designated field (e.g., `http://localhost:8080`)
96-
3. Click Save to store the URL
113+
2. Enter the **Southbound URL** (Things API collection endpoint, e.g. `http://localhost:8080/things/`)
114+
3. Enter the **Northbound URL** (Things API collection endpoint exposed by the proxy)
115+
4. Click Save to store the URLs
116+
117+
> ⚠️ Important
118+
> Do **not** paste a full Thing or TD resource URL (e.g. `/things/{id}`).
119+
> Both Northbound and Southbound URLs must point to the **Things API collection endpoint**
120+
> (typically ending with `/things/`).
121+
> ediTDor automatically appends the Thing/TD identifier when sending or fetching data.
97122
98123
The proxy uses the TD sent to its southbound API endpoint to communicate with a Thing. This way, you can interact with a non-HTTP Thing from your ediTDor.
99124

src/components/Dialogs/AddLinkTdDialog.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,14 @@ const AddLinkTdDialog = forwardRef<AddLinkTdDialogRef, AddLinkTdDialogProps>(
8080
};
8181

8282
const addLinksToTd = (link: Link): void => {
83-
tdJSON["links"] = [...(tdJSON["links"] ? tdJSON["links"] : []), link];
84-
context.updateOfflineTD(JSON.stringify(tdJSON, null, 2));
83+
// clone instead of mutating original TD
84+
const updatedTd = structuredClone(context.parsedTD);
85+
// initialize links array if missing
86+
if (!Array.isArray(updatedTd.links)) {
87+
updatedTd.links = [];
88+
}
89+
updatedTd.links.push(link);
90+
context.updateOfflineTD(JSON.stringify(updatedTd, null, 2));
8591
};
8692

8793
const linkingMethodChange = (linkingOption: string): void => {
@@ -243,6 +249,8 @@ const AddLinkTdDialog = forwardRef<AddLinkTdDialogRef, AddLinkTdDialogProps>(
243249
return;
244250
}
245251

252+
const linkedTd: Record<string, any> = {};
253+
246254
const link: Link = {
247255
href:
248256
(
@@ -272,7 +280,7 @@ const AddLinkTdDialog = forwardRef<AddLinkTdDialogRef, AddLinkTdDialogProps>(
272280
) {
273281
try {
274282
var httpRequest = new XMLHttpRequest();
275-
httpRequest.open("GET", href, false);
283+
httpRequest.open("GET", link.href, false);
276284
httpRequest.send();
277285
if (
278286
httpRequest
@@ -286,10 +294,10 @@ const AddLinkTdDialog = forwardRef<AddLinkTdDialogRef, AddLinkTdDialogProps>(
286294
} catch (ex) {
287295
const msg = "We ran into an error trying to fetch your TD.";
288296
console.error(msg, ex);
289-
linkedTd[href] = currentLinkedTd;
297+
linkedTd[link.href] = currentLinkedTd;
290298
}
291299
} else {
292-
linkedTd[href] = currentLinkedTd;
300+
linkedTd[link.href] = currentLinkedTd;
293301
}
294302

295303
if (link.href === "") {

src/components/Dialogs/ContributeToCatalogDialog.tsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ const VALIDATION_TM_JSON =
5757
"https://raw.githubusercontent.com/wot-oss/tmc/main/internal/commands/validate/tm-json-schema-validation.json";
5858
const VALIDATION_MODBUS =
5959
"https://raw.githubusercontent.com/wot-oss/tmc/refs/heads/main/internal/commands/validate/modbus.schema.json";
60+
const VALIDATION_MODBUS_OLD =
61+
"https://raw.githubusercontent.com/wot-oss/tmc/main/internal/commands/validate/modbus-old.schema.json";
6062

6163
const ContributeToCatalogDialog = forwardRef((props, ref) => {
6264
const context = useContext(ediTDorContext);
@@ -286,6 +288,19 @@ const ContributeToCatalogDialog = forwardRef((props, ref) => {
286288
throw new Error(message);
287289
}
288290

291+
response = await fetch(VALIDATION_MODBUS_OLD);
292+
if (!response.ok)
293+
throw new Error(`Failed to fetch schema from ${VALIDATION_MODBUS_OLD}`);
294+
schema = await response.json();
295+
validate = ajv.compile(schema);
296+
valid = validate(tdTransformed);
297+
if (!valid) {
298+
let message = `Validation failed for ${VALIDATION_MODBUS_OLD}: ${
299+
validate.errors ? ajv.errorsText(validate.errors) : ""
300+
}`;
301+
throw new Error(message);
302+
}
303+
289304
dispatch({ type: "SET_BACKGROUND_TD_TO_SEND", payload: tdTransformed });
290305
dispatch({ type: "SET_METADATA_ERROR_MESSAGE", payload: "" });
291306
dispatch({ type: "SET_METADATA_VALIDATION", payload: "VALID" });

src/components/Editor/JsonEditor.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ import { IValidationMessage } from "../../types/context";
2727
type SchemaMapMessage = Map<string, Record<string, unknown>>;
2828

2929
// List of all Options can be found here: https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneEditorConstructionOptions.html
30+
const editorOptions: editor.IStandaloneEditorConstructionOptions = {
31+
selectOnLineNumbers: true,
32+
automaticLayout: true,
33+
lineDecorationsWidth: 20,
34+
tabSize: 2,
35+
insertSpaces: true,
36+
};
3037

3138
// delay function that executes the callback once it hasn't been called for
3239
// at least x ms.

0 commit comments

Comments
 (0)