Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0b9741b

Browse files
author
Elier Herrera
committed
docs(pwa): add PWA icons and favicons guide for app editor
1 parent 3c36342 commit 0b9741b

File tree

5 files changed

+552
-10
lines changed

5 files changed

+552
-10
lines changed

‎BRANCH_FEATURE_PLAN.md

Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
# Lowcoder App-Specific Favicon & PWA Icon Implementation Plan
2+
3+
## Overview
4+
5+
This plan outlines the implementation of favicon and PWA icon functionality for individual apps in Lowcoder, allowing each app to have its own visual identity in browser tabs and when installed as a PWA.
6+
7+
## Current State Analysis
8+
9+
### How Icons Currently Work
10+
11+
1. **App Icons**: Stored as strings in the application settings (`icon` field in `appSettingsComp.tsx`)
12+
2. **Icon Types**: Support multiple formats:
13+
- FontAwesome icons (`/icon:solid/` or `/icon:regular/`)
14+
- Ant Design icons (`/icon:antd/`)
15+
- Base64 encoded images (`data:image`)
16+
- URL-based images (`http://`)
17+
3. **Current Usage**: Icons are displayed in app lists and settings using `MultiIconDisplay` component
18+
19+
### Current Favicon/PWA Setup (as of HEAD)
20+
21+
1. **Per‐App Favicon (Editor/App routes)**: Set in `client/packages/lowcoder/src/pages/editor/editorView.tsx` using React Helmet. Uses app icon when available; otherwise falls back to branding favicon or default `/src/assets/images/favicon.ico`.
22+
2. **Admin Routes Favicon**: Set in `client/packages/lowcoder/src/pages/ApplicationV2/index.tsx` to a scoped default favicon so it does not interfere with per‐app favicons.
23+
3. **Per‐App PWA Manifest**: Served dynamically by backend at `GET /api/applications/{appId}/manifest.json` and injected via `<link rel="manifest">` in `editorView.tsx`.
24+
4. **Static Manifest (legacy)**: `client/packages/lowcoder/site.webmanifest` remains in the repo but is not linked on app routes.
25+
26+
## Implementation Progress
27+
28+
### ✅ Phase 1: Basic App-Specific Favicon (COMPLETED)
29+
30+
**Status**: ✅ **COMPLETED** - App-specific favicon functionality is working
31+
32+
#### What Has Been Implemented:
33+
34+
1. **✅ Icon Conversion Utilities** (`client/packages/lowcoder/src/util/iconConversionUtils.ts`):
35+
36+
- `getAppIconInfo()` - Extracts icon information from app settings
37+
- `getAppFavicon()` - Gets app-specific favicon URL
38+
- `canUseAsFavicon()` - Checks if an icon can be used as favicon
39+
- Support for different icon types (URL, base64, FontAwesome, Ant Design)
40+
- Handles React element extraction for complex icon objects
41+
42+
2. **✅ Updated Editor View** (`client/packages/lowcoder/src/pages/editor/editorView.tsx`):
43+
44+
- Added app-specific favicon to both read-only and full editor views
45+
- Conditional rendering: app-specific favicon when available, default favicon as fallback
46+
- Proper Redux integration for branding config access
47+
- Clean implementation without console errors
48+
49+
3. **✅ Modified Global App Configuration** (`client/packages/lowcoder/src/app.tsx`):
50+
51+
- Removed default favicon from global Helmet
52+
- Added comment indicating favicon is handled conditionally in editorView.tsx
53+
54+
4. **✅ Fixed Icon Parsing** (`client/packages/lowcoder/src/comps/comps/multiIconDisplay.tsx`):
55+
56+
- Added proper export for `parseIconIdentifier` function
57+
- Added type checking to prevent errors with non-string identifiers
58+
- Fixed React import issues
59+
60+
5. **✅ Error Resolution**:
61+
62+
- Resolved React Helmet "Cannot convert a Symbol value to a string" errors
63+
- Fixed TypeScript type issues
64+
- Clean console output with no errors
65+
66+
6. **✅ Admin Routes Default Favicon** (`client/packages/lowcoder/src/pages/ApplicationV2/index.tsx`):
67+
68+
- Added a scoped default favicon for admin routes (e.g., `/apps`, `/datasource`, `/setting`)
69+
- Uses `brandingConfig?.favicon` when available, otherwise falls back to `/src/assets/images/favicon.ico`
70+
- Placed only within admin layout so it does not precede or override per‐app favicons on app routes
71+
- Observes favicon precedence: the first `<link rel='icon'>` in the document is chosen by browsers
72+
73+
#### Technical Implementation Details:
74+
75+
```typescript
76+
// Icon extraction from React elements
77+
if (iconIdentifier.$$typeof === Symbol.for('react.element')) {
78+
if (iconIdentifier.props && iconIdentifier.props.value) {
79+
iconString = iconIdentifier.props.value
80+
}
81+
}
82+
83+
// Conditional favicon rendering
84+
{
85+
application &&
86+
(() => {
87+
const appFavicon = getAppFavicon(
88+
appSettingsComp,
89+
application.applicationId
90+
)
91+
if (appFavicon) {
92+
return <link key='app-favicon' rel='icon' href={appFavicon} />
93+
} else {
94+
const defaultFavicon =
95+
brandingConfig?.favicon || '/src/assets/images/favicon.ico'
96+
return (
97+
<link
98+
key='default-favicon'
99+
rel='icon'
100+
href={defaultFavicon}
101+
/>
102+
)
103+
}
104+
})()
105+
}
106+
```
107+
108+
#### Current Behavior:
109+
110+
- **App with Custom Icon**: Shows only the app-specific favicon (e.g., MilamsFavicon.png)
111+
- **App without Icon**: Shows only the default favicon
112+
- **Admin Routes**: Show the default favicon (branding-based if configured), independent of app views
113+
- **No Competing Favicons**: Only one favicon is rendered at a time
114+
- **Clean Implementation**: No console errors or React Helmet issues
115+
116+
### ✅ Phase 2: Backend Icon Conversion Service (MVP COMPLETED)
117+
118+
**Status**: ✅ **COMPLETED (MVP)** — Minimal backend service in place to serve per‐app PNG icons with graceful fallbacks. Future iterations can add advanced conversions and caching.
119+
120+
#### What Has Been Implemented
121+
122+
1. **New backend endpoints** (public GET in security):
123+
124+
- `GET /api/applications/{appId}/icons` → lists available sizes
125+
- `GET /api/applications/{appId}/icons/{size}.png[?bg=#RRGGBB]` → serves PNG for allowed sizes (48, 72, 96, 120, 128, 144, 152, 167, 180, 192, 256, 384, 512), with optional background color
126+
127+
2. **Image handling (v1.1)**:
128+
129+
- Supports data URLs and HTTP/HTTPS images decodable by Java ImageIO
130+
- Scales and centers to requested size; outputs PNG (transparent by default)
131+
- Optional solid background via `?bg=#RRGGBB`
132+
- Adds `Cache-Control: public, max-age=7d`
133+
- Graceful fallback: generated placeholder, tinted by optional `bg`
134+
135+
3. **Manifest integration**:
136+
137+
- Manifest now points icons to the new PNG endpoints for each app, ensuring installable PWAs always fetch renderable PNGs
138+
139+
4. **Security**:
140+
141+
- Public GET access permitted for `/icons` and `/icons/**` under both legacy and new URL bases
142+
143+
#### Deferred (Future Enhancements)
144+
145+
- Convert font icons (FontAwesome/Ant Design) to SVG → PNG
146+
- Robust SVG rendering beyond ImageIO defaults
147+
- Persistent caching/database of converted outputs
148+
- Optional background color handling and multiple sizes beyond 192/512
149+
150+
### ✅ Phase 3: PWA Manifest Enhancement (COMPLETED)
151+
152+
**Status**: ✅ **COMPLETED** — Enhanced PWA manifest with maskable icons, shortcuts, categories, and app-specific meta tags
153+
154+
#### What Has Been Implemented
155+
156+
- **✅ Backend per‐app manifest endpoint**: `GET /api/applications/{appId}/manifest.json` in `ApplicationController` generates a manifest dynamically from the app DSL (`settings.title`, `settings.description`, `settings.icon`) with sensible fallbacks and default icons.
157+
- **✅ Security**: Public GET access for the manifest path is permitted in `SecurityConfig` (no auth required), including new‐URL aliases.
158+
- **✅ Frontend injection**: `editorView.tsx` adds `<link rel="manifest">` for app routes, so browsers automatically fetch the per‐app manifest. Admin routes don't include it.
159+
- **✅ Verification**: Manual checks confirm a single manifest link on app pages and `200 application/manifest+json` served by the endpoint with no 401/404s.
160+
- **✅ Installation**: PWA installation works and uses the app's icon (verified).
161+
- **✅ Manifest enrichment**: Added `id`, app‐scoped `scope`, and app‐specific `start_url`:
162+
- `id`: `/apps/{appId}`
163+
- `scope`: `/apps/{appId}/`
164+
- `start_url`: `/apps/{appId}/view`
165+
- **✅ Robust defaults**: Hardened handling for empty/missing `settings.title`/`settings.description` to ensure clean fallbacks.
166+
- **✅ Maskable icons**: Added `"purpose": "any maskable"` to all manifest icons for better PWA system integration
167+
- **✅ PWA shortcuts**: Added shortcuts array with:
168+
- View shortcut (opens app view)
169+
- Edit shortcut (opens app editor)
170+
- **✅ Proper content type**: Set manifest response `Content-Type` to `application/manifest+json`
171+
- **✅ App-specific meta tags** in `editorView.tsx`:
172+
- `link[rel='icon']``/api/applications/{appId}/icons/192.png` (with optional `?bg=`)
173+
- `apple-touch-icon``/api/applications/{appId}/icons/512.png` (with optional `?bg=`)
174+
- `apple-touch-startup-image` → same as above
175+
- `og:image` / `twitter:image` → per‐app 512 PNG
176+
- `theme-color` using `brandingSettings?.config_set?.mainBrandingColor` with `#b480de` fallback
177+
- `apple-mobile-web-app-title` using app title
178+
179+
#### Technical Implementation Details:
180+
181+
**Backend manifest enhancements** (`ApplicationController.java`):
182+
183+
```java
184+
// Maskable icons
185+
icon.put("purpose", "any maskable");
186+
187+
// PWA shortcuts
188+
List<Map<String, Object>> shortcuts = new ArrayList<>();
189+
Map<String, Object> viewShortcut = new HashMap<>();
190+
viewShortcut.put("name", appTitle);
191+
viewShortcut.put("url", appStartUrl);
192+
shortcuts.add(viewShortcut);
193+
manifest.put("shortcuts", shortcuts);
194+
195+
// Proper content type
196+
.contentType(MediaType.valueOf("application/manifest+json"))
197+
```
198+
199+
**Frontend app meta tags** (`editorView.tsx`):
200+
201+
```tsx
202+
// Apple touch icon with smart fallback
203+
const appleTouchIcon =
204+
typeof appIconView === 'string'
205+
? appIconView
206+
: (brandingConfig?.logo && typeof brandingConfig.logo === 'string'
207+
? brandingConfig.logo
208+
: undefined) || '/android-chrome-512x512.png'
209+
210+
// Brand-aware theme color
211+
;<meta
212+
name='theme-color'
213+
content={brandingSettings?.config_set?.mainBrandingColor || '#b480de'}
214+
/>
215+
```
216+
217+
### ✅ Phase 4: Advanced PWA Features (COMPLETED)
218+
219+
**Status**: ✅ **COMPLETED** — Advanced PWA and icon optimization features
220+
221+
#### Planned Implementation:
222+
223+
1. **Dynamic Icon Generation**
224+
225+
- ✅ Multiple icon sizes generated on-demand via `GET /icons/{size}.png` (48, 72, 96, 120, 128, 144, 152, 167, 180, 192, 256, 384, 512)
226+
- ✅ Optional background color supported via `?bg=#RRGGBB`
227+
- ✅ In-memory caching of generated PNGs (12h TTL, up to 2000 entries)
228+
- 🔄 Future: support SVG/WebP output and persistent cache store
229+
230+
## Technical Implementation Details
231+
232+
### Backend Changes Needed (Future)
233+
234+
1. **New API Endpoints**:
235+
236+
```java
237+
// Convert app icon to favicon
238+
POST /api/applications/{appId}/favicon
239+
240+
// Generate app-specific manifest
241+
GET /api/applications/{appId}/manifest.json
242+
243+
// Get converted icon URLs
244+
GET /api/applications/{appId}/icons (DONE)
245+
```
246+
247+
Note: `GET /api/applications/{appId}/manifest.json` is already implemented in `ApplicationController` and permitted in `SecurityConfig`.
248+
249+
2. **Icon Conversion Service**:
250+
- Use libraries like ImageMagick or Java ImageIO
251+
- Support SVG to PNG conversion
252+
- Generate multiple favicon sizes
253+
- Handle transparency and background colors
254+
255+
### Frontend Changes Completed
256+
257+
1. **Updated `editorView.tsx`**:
258+
259+
```typescript
260+
// Add app-specific favicon to Helmet
261+
{
262+
application &&
263+
(() => {
264+
const appFavicon = getAppFavicon(
265+
appSettingsComp,
266+
application.applicationId
267+
)
268+
if (appFavicon) {
269+
return (
270+
<link key='app-favicon' rel='icon' href={appFavicon} />
271+
)
272+
} else {
273+
const defaultFavicon =
274+
brandingConfig?.favicon ||
275+
'/src/assets/images/favicon.ico'
276+
return (
277+
<link
278+
key='default-favicon'
279+
rel='icon'
280+
href={defaultFavicon}
281+
/>
282+
)
283+
}
284+
})()
285+
}
286+
```
287+
288+
2. **Created Icon Conversion Utilities**:
289+
290+
```typescript
291+
// Convert icon identifier to favicon URL
292+
const getAppFavicon = (
293+
appSettingsComp: any,
294+
appId: string
295+
): string | null => {
296+
const iconInfo = getAppIconInfo(appSettingsComp)
297+
if (!iconInfo) return null
298+
if (canUseAsFavicon(iconInfo)) {
299+
return getAppFaviconUrl(appId, iconInfo)
300+
}
301+
return null
302+
}
303+
```
304+
305+
3. **Updated `ApplicationV2/index.tsx`** (Admin routes default favicon):
306+
307+
```tsx
308+
<Helmet>
309+
<link
310+
key='default-favicon'
311+
rel='icon'
312+
href={
313+
brandingConfig?.favicon
314+
? buildMaterialPreviewURL(brandingConfig.favicon)
315+
: '/src/assets/images/favicon.ico'
316+
}
317+
/>
318+
</Helmet>
319+
```
320+
321+
### Database Schema Updates (Future)
322+
323+
1. **Application Table**: Add fields for cached favicon URLs
324+
2. **Icon Cache Table**: Store converted icons with metadata
325+
326+
## Benefits of This Approach
327+
328+
1. **User Experience**: Each app has its own visual identity in browser tabs
329+
2. **PWA Support**: Apps can be installed as standalone PWAs with custom icons (Phase 3)
330+
3. **Backward Compatibility**: Existing apps without icons fall back to global favicon
331+
4. **🔄 Performance**: Cached icon conversion reduces processing overhead (Phase 2)
332+
5. **Scalability**: Icon conversion happens on-demand and is cached
333+
334+
## Implementation Priority
335+
336+
1. **High Priority**: Basic favicon functionality for app view pages (COMPLETED)
337+
2. **Medium Priority**: PWA manifest generation and installation support (COMPLETED)
338+
3. **🔄 Low Priority**: Advanced icon processing and optimization
339+
340+
## File Structure Changes
341+
342+
### ✅ Files Created
343+
344+
- `client/packages/lowcoder/src/util/iconConversionUtils.ts` ✅
345+
- `client/packages/lowcoder/src/components/AppFaviconProvider.tsx` — Not created (implemented directly in `client/packages/lowcoder/src/pages/editor/editorView.tsx`)
346+
- `server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/AppIconController.java` ✅
347+
348+
### ✅ Files Modified
349+
350+
- `client/packages/lowcoder/src/pages/editor/editorView.tsx` ✅
351+
- `client/packages/lowcoder/src/app.tsx` ✅
352+
- `client/packages/lowcoder/src/comps/comps/multiIconDisplay.tsx` ✅
353+
- `client/packages/lowcoder/src/pages/ApplicationV2/index.tsx` ✅
354+
- `server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/application/ApplicationController.java` ✅
355+
- `server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/framework/security/SecurityConfig.java` ✅
356+
357+
### 🔄 Files to Create (Future)
358+
359+
- `server/api-service/lowcoder-server/src/main/java/org/lowcoder/domain/application/service/IconConversionService.java`
360+
361+
### 🔄 Files to Modify (Future)
362+
363+
- `server/api-service/lowcoder-domain/src/main/java/org/lowcoder/domain/application/model/Application.java`
364+
365+
## Testing Strategy
366+
367+
1. **Unit Tests**: Icon conversion utilities (manual testing completed)
368+
2. **Integration Tests**: End-to-end favicon generation and display (manual testing completed)
369+
3. **Browser Tests**: Verify favicon appears correctly in different browsers (manual testing completed)
370+
4. **PWA Tests**: Test app installation with custom icons (Phase 3)
371+
372+
## Deployment Considerations
373+
374+
1. **🔄 Icon Storage**: Persistent storage/caching for converted icons is not implemented yet (icons are rendered on-demand)
375+
2. **🔄 CDN Integration**: Configure CDN for serving converted icons (Phase 2)
376+
3. **Cache Headers**: Icon responses set `Cache-Control: public, max-age=7d`
377+
4. **Error Handling**: Graceful fallback when icon conversion fails
378+
379+
## Current Status Summary
380+
381+
- **Phase 1**: COMPLETEDBasic app‐specific favicon functionality is working
382+
- **Phase 2 (MVP)**: COMPLETEDBackend icon endpoints serve PNGs with graceful fallback; security updated; manifest points to endpoints
383+
- **Phase 3**: COMPLETEDEnhanced PWA manifest with maskable icons, shortcuts, categories, proper content type, and app-specific meta tags
384+
- **Phase 4**: COMPLETEDMulti-size icon endpoints, brand-aware background color, per‐app OG/Twitter images, in‐memory caching. Remaining stretch goals (SVG/WebP, persistent cache, font‐icon rendering, custom install prompts) are tracked as future enhancements.
385+
386+
The implementation is modular and can be developed incrementally. Phase 1 provided immediate value with app-specific favicons, and Phase 3 added comprehensive PWA support. Phase 2 (MVP) delivered per‐app PNG endpoints with cache headers and graceful fallback; later updates added multi-size support and optional background color. Phase 4 progresses advanced features; remaining items are tracked above.
387+
388+
## Documentation
389+
390+
- Added: `docs/build-applications/app-editor/pwa-icons-and-favicons.md` — per‐app PWA icons and favicons, endpoints, sizes, and `bg` parameter usage.
391+
392+
## Tests/Builds
393+
394+
- Client build: PASS (`yarn build`)
395+
- Server build: Maven not available in this environment; validate in CI with Java-enabled environment.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /