@djangocfg/layouts 2.0.10 → 2.0.11
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/layouts",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.11",
|
|
4
4
|
"description": "Simple, straightforward layout components for Next.js - import and use with props",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"layouts",
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
"check": "tsc --noEmit"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
|
-
"@djangocfg/api": "^1.4.
|
|
96
|
-
"@djangocfg/centrifugo": "^1.4.
|
|
97
|
-
"@djangocfg/ui": "^1.4.
|
|
95
|
+
"@djangocfg/api": "^1.4.41",
|
|
96
|
+
"@djangocfg/centrifugo": "^1.4.41",
|
|
97
|
+
"@djangocfg/ui": "^1.4.41",
|
|
98
98
|
"@hookform/resolvers": "^5.2.0",
|
|
99
99
|
"consola": "^3.4.2",
|
|
100
100
|
"lucide-react": "^0.545.0",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"uuid": "^11.1.0"
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
|
-
"@djangocfg/typescript-config": "^1.4.
|
|
117
|
+
"@djangocfg/typescript-config": "^1.4.41",
|
|
118
118
|
"@types/node": "^24.7.2",
|
|
119
119
|
"@types/react": "19.2.2",
|
|
120
120
|
"@types/react-dom": "19.2.1",
|
package/src/components/index.ts
CHANGED
|
@@ -46,7 +46,6 @@ import { AuthProvider, type AuthConfig } from '../../auth/context';
|
|
|
46
46
|
import { ErrorTrackingProvider, type ValidationErrorConfig, type CORSErrorConfig, type NetworkErrorConfig } from '../../components/errors/ErrorsTracker';
|
|
47
47
|
import { AnalyticsProvider } from '../../snippets/Analytics';
|
|
48
48
|
import { PageProgress } from '../../components/core/PageProgress';
|
|
49
|
-
import { UpdateNotifier } from '../../components/UpdateNotifier';
|
|
50
49
|
import { Suspense, ClientOnly } from '../../components/core';
|
|
51
50
|
|
|
52
51
|
export type LayoutMode = 'public' | 'private' | 'admin';
|
|
@@ -139,11 +138,6 @@ export interface AppLayoutProps {
|
|
|
139
138
|
supportEmail?: string;
|
|
140
139
|
onError?: (error: Error, errorInfo: React.ErrorInfo) => void;
|
|
141
140
|
};
|
|
142
|
-
|
|
143
|
-
/** Update notifier configuration */
|
|
144
|
-
updateNotifier?: {
|
|
145
|
-
enabled?: boolean;
|
|
146
|
-
};
|
|
147
141
|
}
|
|
148
142
|
|
|
149
143
|
/**
|
|
@@ -160,7 +154,6 @@ function AppLayoutContent({
|
|
|
160
154
|
analytics,
|
|
161
155
|
centrifugo,
|
|
162
156
|
errorBoundary,
|
|
163
|
-
updateNotifier,
|
|
164
157
|
}: AppLayoutProps) {
|
|
165
158
|
const pathname = usePathname();
|
|
166
159
|
|
|
@@ -257,9 +250,6 @@ function AppLayoutContent({
|
|
|
257
250
|
<>
|
|
258
251
|
{content}
|
|
259
252
|
<PageProgress />
|
|
260
|
-
<UpdateNotifier
|
|
261
|
-
enabled={updateNotifier?.enabled !== false}
|
|
262
|
-
/>
|
|
263
253
|
<Toaster />
|
|
264
254
|
</>
|
|
265
255
|
);
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Update Notifier Component
|
|
3
|
-
*
|
|
4
|
-
* Checks npm registry for @djangocfg package updates
|
|
5
|
-
* Shows toast notification when new version is available
|
|
6
|
-
* Uses localStorage to cache check and avoid spam
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
'use client';
|
|
10
|
-
|
|
11
|
-
import React, { useEffect, useState, useRef } from 'react';
|
|
12
|
-
import consola from 'consola';
|
|
13
|
-
import { toast } from '@djangocfg/ui/hooks';
|
|
14
|
-
import { useLocalStorage } from '@djangocfg/ui/hooks';
|
|
15
|
-
|
|
16
|
-
const PACKAGE_NAME = '@djangocfg/layouts';
|
|
17
|
-
const CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
18
|
-
const CACHE_KEY = 'djangocfg_update_check';
|
|
19
|
-
|
|
20
|
-
interface UpdateCheckCache {
|
|
21
|
-
lastCheck: number;
|
|
22
|
-
latestVersion: string;
|
|
23
|
-
dismissed: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const defaultCache: UpdateCheckCache = {
|
|
27
|
-
lastCheck: 0,
|
|
28
|
-
latestVersion: '',
|
|
29
|
-
dismissed: false,
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export interface UpdateNotifierProps {
|
|
33
|
-
/**
|
|
34
|
-
* Enable update notifications
|
|
35
|
-
* @default false
|
|
36
|
-
*/
|
|
37
|
-
enabled?: boolean;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Get current package version from package.json
|
|
42
|
-
* Uses require in runtime to avoid TypeScript rootDir issues
|
|
43
|
-
*/
|
|
44
|
-
function getCurrentVersion(): string | null {
|
|
45
|
-
try {
|
|
46
|
-
// Use require in runtime (works in both dev and build)
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
48
|
-
const packageJson = require('../../../package.json');
|
|
49
|
-
return packageJson.version || null;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
consola.warn('[UpdateNotifier] Failed to load package.json:', error);
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Compare semver versions
|
|
58
|
-
* Returns true if newVersion > currentVersion
|
|
59
|
-
*/
|
|
60
|
-
function isNewerVersion(current: string, latest: string): boolean {
|
|
61
|
-
const parseCurrent = current.split('.').map(Number);
|
|
62
|
-
const parseLatest = latest.split('.').map(Number);
|
|
63
|
-
|
|
64
|
-
for (let i = 0; i < 3; i++) {
|
|
65
|
-
if (parseLatest[i] > parseCurrent[i]) return true;
|
|
66
|
-
if (parseLatest[i] < parseCurrent[i]) return false;
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Fetch latest version from npm registry
|
|
73
|
-
*/
|
|
74
|
-
async function fetchLatestVersion(): Promise<string | null> {
|
|
75
|
-
try {
|
|
76
|
-
const response = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
|
|
77
|
-
method: 'GET',
|
|
78
|
-
headers: { 'Accept': 'application/json' },
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
if (!response.ok) return null;
|
|
82
|
-
|
|
83
|
-
const data = await response.json();
|
|
84
|
-
return data.version || null;
|
|
85
|
-
} catch (error) {
|
|
86
|
-
consola.warn('[UpdateNotifier] Failed to check for updates:', error);
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
export function UpdateNotifier({ enabled = false }: UpdateNotifierProps) {
|
|
92
|
-
const [checked, setChecked] = useState(false);
|
|
93
|
-
const [cache, setCache] = useLocalStorage<UpdateCheckCache | null>(CACHE_KEY, null);
|
|
94
|
-
const cacheRef = useRef(cache);
|
|
95
|
-
|
|
96
|
-
// Keep cacheRef in sync with cache
|
|
97
|
-
useEffect(() => {
|
|
98
|
-
cacheRef.current = cache;
|
|
99
|
-
}, [cache]);
|
|
100
|
-
|
|
101
|
-
useEffect(() => {
|
|
102
|
-
if (!enabled || checked || typeof window === 'undefined') return;
|
|
103
|
-
|
|
104
|
-
const checkForUpdates = async () => {
|
|
105
|
-
// Get current version from package.json
|
|
106
|
-
const currentVersion = getCurrentVersion();
|
|
107
|
-
if (!currentVersion) {
|
|
108
|
-
setChecked(true);
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Check cache first (use ref to get latest value)
|
|
113
|
-
const now = Date.now();
|
|
114
|
-
const cachedData = cacheRef.current || defaultCache;
|
|
115
|
-
|
|
116
|
-
// If we checked recently, skip
|
|
117
|
-
if (cachedData && cachedData.lastCheck > 0 && (now - cachedData.lastCheck) < CHECK_INTERVAL_MS) {
|
|
118
|
-
// Show notification if there's an update and it wasn't dismissed
|
|
119
|
-
if (cachedData.latestVersion && !cachedData.dismissed && isNewerVersion(currentVersion, cachedData.latestVersion)) {
|
|
120
|
-
showUpdateNotification(currentVersion, cachedData.latestVersion, setCache);
|
|
121
|
-
}
|
|
122
|
-
setChecked(true);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Fetch latest version from npm
|
|
127
|
-
const latestVersion = await fetchLatestVersion();
|
|
128
|
-
|
|
129
|
-
if (!latestVersion) {
|
|
130
|
-
setChecked(true);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Update cache
|
|
135
|
-
setCache({
|
|
136
|
-
lastCheck: now,
|
|
137
|
-
latestVersion,
|
|
138
|
-
dismissed: false,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Show notification if newer version available
|
|
142
|
-
if (isNewerVersion(currentVersion, latestVersion)) {
|
|
143
|
-
showUpdateNotification(currentVersion, latestVersion, setCache);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
setChecked(true);
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
// Check after a short delay to not block initial render
|
|
150
|
-
const timer = setTimeout(checkForUpdates, 2000);
|
|
151
|
-
|
|
152
|
-
return () => clearTimeout(timer);
|
|
153
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
154
|
-
}, [enabled, checked]);
|
|
155
|
-
|
|
156
|
-
return null; // This component doesn't render anything
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* Show update notification toast
|
|
161
|
-
*/
|
|
162
|
-
function showUpdateNotification(
|
|
163
|
-
currentVersion: string,
|
|
164
|
-
latestVersion: string,
|
|
165
|
-
setCache: (value: UpdateCheckCache | null | ((val: UpdateCheckCache | null) => UpdateCheckCache | null)) => void
|
|
166
|
-
) {
|
|
167
|
-
toast({
|
|
168
|
-
title: `📦 Update Available`,
|
|
169
|
-
description: `New version ${latestVersion} of @djangocfg packages is available. You're using ${currentVersion}. Run: pnpm update @djangocfg/layouts@latest`,
|
|
170
|
-
duration: 10000,
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
// Mark as dismissed in cache after showing
|
|
174
|
-
setCache((prev) => {
|
|
175
|
-
if (!prev) return null;
|
|
176
|
-
return { ...prev, dismissed: true };
|
|
177
|
-
});
|
|
178
|
-
}
|