datajunction-ui 0.0.27 → 0.0.30
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 +1 -1
- package/src/__tests__/reportWebVitals.test.ts +27 -0
- package/src/app/components/NamespaceHeader.jsx +85 -26
- package/src/app/components/__tests__/NamespaceHeader.test.jsx +144 -0
- package/src/app/components/__tests__/NotificationBell.test.tsx +23 -0
- package/src/app/components/djgraph/__tests__/DJNode.test.tsx +36 -0
- package/src/app/icons/__tests__/Icons.test.jsx +24 -0
- package/src/app/pages/NamespacePage/Explorer.jsx +68 -10
- package/src/app/pages/NamespacePage/__tests__/index.test.jsx +21 -11
- package/src/app/pages/NamespacePage/index.jsx +625 -48
- package/src/app/pages/NotificationsPage/__tests__/index.test.jsx +28 -0
- package/src/app/pages/OverviewPage/OverviewPanel.jsx +1 -3
- package/src/app/pages/QueryPlannerPage/PreAggDetailsPanel.jsx +20 -20
- package/src/app/pages/QueryPlannerPage/index.jsx +1 -1
- package/src/app/pages/Root/__tests__/index.test.jsx +99 -4
- package/src/app/pages/SQLBuilderPage/__tests__/index.test.jsx +177 -0
- package/src/app/pages/SettingsPage/__tests__/CreateServiceAccountModal.test.jsx +50 -0
- package/src/app/pages/SettingsPage/__tests__/NotificationSubscriptionsSection.test.jsx +95 -0
- package/src/app/pages/SettingsPage/__tests__/index.test.jsx +315 -28
- package/src/app/providers/UserProvider.tsx +1 -5
- package/src/app/services/DJService.js +48 -2
- package/src/app/utils/__tests__/date.test.js +60 -140
- package/src/styles/index.css +51 -10
|
@@ -9,6 +9,7 @@ import AddNodeDropdown from '../../components/AddNodeDropdown';
|
|
|
9
9
|
import NodeListActions from '../../components/NodeListActions';
|
|
10
10
|
import LoadingIcon from '../../icons/LoadingIcon';
|
|
11
11
|
import CompactSelect from './CompactSelect';
|
|
12
|
+
import { getDJUrl } from '../../services/DJService';
|
|
12
13
|
|
|
13
14
|
import 'styles/node-list.css';
|
|
14
15
|
import 'styles/sorted-table.css';
|
|
@@ -64,6 +65,7 @@ export function NamespacePage() {
|
|
|
64
65
|
|
|
65
66
|
const [filters, setFilters] = useState(getFiltersFromUrl);
|
|
66
67
|
const [moreFiltersOpen, setMoreFiltersOpen] = useState(false);
|
|
68
|
+
const [deploymentsDropdownOpen, setDeploymentsDropdownOpen] = useState(false);
|
|
67
69
|
|
|
68
70
|
// Sync filters state when URL changes
|
|
69
71
|
useEffect(() => {
|
|
@@ -166,6 +168,9 @@ export function NamespacePage() {
|
|
|
166
168
|
const [retrieved, setRetrieved] = useState(false);
|
|
167
169
|
|
|
168
170
|
const [namespaceHierarchy, setNamespaceHierarchy] = useState([]);
|
|
171
|
+
const [namespaceSources, setNamespaceSources] = useState({});
|
|
172
|
+
const [currentNamespaceSources, setCurrentNamespaceSources] = useState(null);
|
|
173
|
+
const [recentDeployments, setRecentDeployments] = useState([]);
|
|
169
174
|
|
|
170
175
|
const [sortConfig, setSortConfig] = useState({
|
|
171
176
|
key: 'updatedAt',
|
|
@@ -230,10 +235,41 @@ export function NamespacePage() {
|
|
|
230
235
|
const namespaces = await djClient.namespaces();
|
|
231
236
|
const hierarchy = createNamespaceHierarchy(namespaces);
|
|
232
237
|
setNamespaceHierarchy(hierarchy);
|
|
238
|
+
|
|
239
|
+
// Fetch sources for all namespaces in bulk
|
|
240
|
+
const allNamespaceNames = namespaces.map(ns => ns.namespace);
|
|
241
|
+
if (allNamespaceNames.length > 0) {
|
|
242
|
+
const sourcesResponse = await djClient.namespaceSourcesBulk(
|
|
243
|
+
allNamespaceNames,
|
|
244
|
+
);
|
|
245
|
+
if (sourcesResponse && sourcesResponse.sources) {
|
|
246
|
+
setNamespaceSources(sourcesResponse.sources);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
233
249
|
};
|
|
234
250
|
fetchData().catch(console.error);
|
|
235
251
|
}, [djClient, djClient.namespaces]);
|
|
236
252
|
|
|
253
|
+
// Fetch sources for the current namespace (for the header badge)
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
const fetchCurrentSources = async () => {
|
|
256
|
+
if (namespace) {
|
|
257
|
+
const sources = await djClient.namespaceSources(namespace);
|
|
258
|
+
setCurrentNamespaceSources(sources);
|
|
259
|
+
|
|
260
|
+
// Fetch recent deployments for this namespace
|
|
261
|
+
try {
|
|
262
|
+
const deployments = await djClient.listDeployments(namespace, 5);
|
|
263
|
+
setRecentDeployments(deployments || []);
|
|
264
|
+
} catch (err) {
|
|
265
|
+
console.error('Failed to fetch deployments:', err);
|
|
266
|
+
setRecentDeployments([]);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
fetchCurrentSources().catch(console.error);
|
|
271
|
+
}, [djClient, namespace]);
|
|
272
|
+
|
|
237
273
|
useEffect(() => {
|
|
238
274
|
const fetchData = async () => {
|
|
239
275
|
setRetrieved(false);
|
|
@@ -458,7 +494,6 @@ export function NamespacePage() {
|
|
|
458
494
|
}}
|
|
459
495
|
>
|
|
460
496
|
<h2 style={{ margin: 0 }}>Explore</h2>
|
|
461
|
-
<AddNodeDropdown namespace={namespace} />
|
|
462
497
|
</div>
|
|
463
498
|
|
|
464
499
|
{/* Unified Filter Bar */}
|
|
@@ -466,7 +501,7 @@ export function NamespacePage() {
|
|
|
466
501
|
style={{
|
|
467
502
|
marginBottom: '1rem',
|
|
468
503
|
padding: '1rem',
|
|
469
|
-
backgroundColor: '#
|
|
504
|
+
backgroundColor: '#f8fafc',
|
|
470
505
|
borderRadius: '8px',
|
|
471
506
|
}}
|
|
472
507
|
>
|
|
@@ -482,7 +517,17 @@ export function NamespacePage() {
|
|
|
482
517
|
<div
|
|
483
518
|
style={{ display: 'flex', alignItems: 'center', gap: '6px' }}
|
|
484
519
|
>
|
|
485
|
-
<span
|
|
520
|
+
<span
|
|
521
|
+
style={{
|
|
522
|
+
fontSize: '11px',
|
|
523
|
+
fontWeight: '600',
|
|
524
|
+
textTransform: 'uppercase',
|
|
525
|
+
letterSpacing: '0.5px',
|
|
526
|
+
color: '#64748b',
|
|
527
|
+
}}
|
|
528
|
+
>
|
|
529
|
+
Quick
|
|
530
|
+
</span>
|
|
486
531
|
{presets.map(preset => (
|
|
487
532
|
<button
|
|
488
533
|
key={preset.id}
|
|
@@ -745,18 +790,23 @@ export function NamespacePage() {
|
|
|
745
790
|
</div>
|
|
746
791
|
|
|
747
792
|
<div className="table-responsive">
|
|
748
|
-
<div
|
|
793
|
+
<div
|
|
794
|
+
className={`sidebar`}
|
|
795
|
+
style={{ borderRight: '1px solid #e2e8f0', paddingRight: '1rem' }}
|
|
796
|
+
>
|
|
749
797
|
<div
|
|
750
798
|
style={{
|
|
751
|
-
|
|
799
|
+
paddingBottom: '12px',
|
|
800
|
+
marginBottom: '8px',
|
|
752
801
|
}}
|
|
753
802
|
>
|
|
754
803
|
<span
|
|
755
804
|
style={{
|
|
756
|
-
|
|
757
|
-
fontSize: '0.8125rem',
|
|
805
|
+
fontSize: '11px',
|
|
758
806
|
fontWeight: '600',
|
|
759
|
-
|
|
807
|
+
textTransform: 'uppercase',
|
|
808
|
+
letterSpacing: '0.5px',
|
|
809
|
+
color: '#64748b',
|
|
760
810
|
}}
|
|
761
811
|
>
|
|
762
812
|
Namespaces
|
|
@@ -770,54 +820,581 @@ export function NamespacePage() {
|
|
|
770
820
|
defaultExpand={true}
|
|
771
821
|
isTopLevel={true}
|
|
772
822
|
key={child.namespace}
|
|
823
|
+
namespaceSources={namespaceSources}
|
|
773
824
|
/>
|
|
774
825
|
))
|
|
775
826
|
: null}
|
|
776
827
|
</div>
|
|
777
|
-
<
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
828
|
+
<div style={{ flex: 1, minWidth: 0, marginLeft: '1.5rem' }}>
|
|
829
|
+
{/* Namespace Header */}
|
|
830
|
+
<div
|
|
831
|
+
style={{
|
|
832
|
+
display: 'flex',
|
|
833
|
+
justifyContent: 'space-between',
|
|
834
|
+
alignItems: 'center',
|
|
835
|
+
paddingBottom: '12px',
|
|
836
|
+
marginBottom: '16px',
|
|
837
|
+
borderBottom: '1px solid #e2e8f0',
|
|
838
|
+
}}
|
|
839
|
+
>
|
|
840
|
+
<div
|
|
841
|
+
style={{ display: 'flex', alignItems: 'center', gap: '8px' }}
|
|
842
|
+
>
|
|
843
|
+
<a href="/" style={{ display: 'flex', alignItems: 'center' }}>
|
|
844
|
+
<svg
|
|
845
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
846
|
+
width="16"
|
|
847
|
+
height="16"
|
|
848
|
+
fill="currentColor"
|
|
849
|
+
viewBox="0 0 16 16"
|
|
850
|
+
>
|
|
851
|
+
<path d="M8.186 1.113a.5.5 0 0 0-.372 0L1.846 3.5 8 5.961 14.154 3.5 8.186 1.113zM15 4.239l-6.5 2.6v7.922l6.5-2.6V4.24zM7.5 14.762V6.838L1 4.239v7.923l6.5 2.6zM7.443.184a1.5 1.5 0 0 1 1.114 0l7.129 2.852A.5.5 0 0 1 16 3.5v8.662a1 1 0 0 1-.629.928l-7.185 2.874a.5.5 0 0 1-.372 0L.63 13.09a1 1 0 0 1-.63-.928V3.5a.5.5 0 0 1 .314-.464L7.443.184z" />
|
|
852
|
+
</svg>
|
|
853
|
+
</a>
|
|
854
|
+
<span style={{ color: '#6c757d' }}>/</span>
|
|
855
|
+
{namespace ? (
|
|
856
|
+
namespace.split('.').map((part, index, arr) => (
|
|
857
|
+
<span
|
|
858
|
+
key={index}
|
|
859
|
+
style={{
|
|
860
|
+
display: 'flex',
|
|
861
|
+
alignItems: 'center',
|
|
862
|
+
gap: '8px',
|
|
863
|
+
}}
|
|
864
|
+
>
|
|
865
|
+
<a
|
|
866
|
+
href={`/namespaces/${arr
|
|
867
|
+
.slice(0, index + 1)
|
|
868
|
+
.join('.')}`}
|
|
869
|
+
style={{
|
|
870
|
+
fontWeight: '400',
|
|
871
|
+
color: '#1e293b',
|
|
872
|
+
textDecoration: 'none',
|
|
873
|
+
}}
|
|
874
|
+
>
|
|
875
|
+
{part}
|
|
876
|
+
</a>
|
|
877
|
+
{index < arr.length - 1 && (
|
|
878
|
+
<span style={{ color: '#94a3b8', fontWeight: '400' }}>
|
|
879
|
+
/
|
|
880
|
+
</span>
|
|
881
|
+
)}
|
|
882
|
+
</span>
|
|
883
|
+
))
|
|
884
|
+
) : (
|
|
885
|
+
<span style={{ fontWeight: '600', color: '#1e293b' }}>
|
|
886
|
+
All Namespaces
|
|
887
|
+
</span>
|
|
888
|
+
)}
|
|
889
|
+
{currentNamespaceSources &&
|
|
890
|
+
currentNamespaceSources.total_deployments > 0 && (
|
|
891
|
+
<div style={{ position: 'relative', marginLeft: '8px' }}>
|
|
783
892
|
<button
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
893
|
+
onClick={() =>
|
|
894
|
+
setDeploymentsDropdownOpen(!deploymentsDropdownOpen)
|
|
895
|
+
}
|
|
896
|
+
style={{
|
|
897
|
+
height: '32px',
|
|
898
|
+
padding: '0 12px',
|
|
899
|
+
fontSize: '12px',
|
|
900
|
+
border: 'none',
|
|
901
|
+
borderRadius: '4px',
|
|
902
|
+
backgroundColor: '#ffffff',
|
|
903
|
+
color: '#0b3d91',
|
|
904
|
+
cursor: 'pointer',
|
|
905
|
+
display: 'flex',
|
|
906
|
+
alignItems: 'center',
|
|
907
|
+
gap: '4px',
|
|
908
|
+
whiteSpace: 'nowrap',
|
|
909
|
+
}}
|
|
787
910
|
>
|
|
788
|
-
{
|
|
911
|
+
{currentNamespaceSources.primary_source?.type ===
|
|
912
|
+
'git' ? (
|
|
913
|
+
<>
|
|
914
|
+
<svg
|
|
915
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
916
|
+
width="12"
|
|
917
|
+
height="12"
|
|
918
|
+
viewBox="0 0 24 24"
|
|
919
|
+
fill="none"
|
|
920
|
+
stroke="currentColor"
|
|
921
|
+
strokeWidth="2"
|
|
922
|
+
strokeLinecap="round"
|
|
923
|
+
strokeLinejoin="round"
|
|
924
|
+
>
|
|
925
|
+
<line x1="6" y1="3" x2="6" y2="15"></line>
|
|
926
|
+
<circle cx="18" cy="6" r="3"></circle>
|
|
927
|
+
<circle cx="6" cy="18" r="3"></circle>
|
|
928
|
+
<path d="M18 9a9 9 0 0 1-9 9"></path>
|
|
929
|
+
</svg>
|
|
930
|
+
Git Managed
|
|
931
|
+
</>
|
|
932
|
+
) : (
|
|
933
|
+
<>
|
|
934
|
+
<svg
|
|
935
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
936
|
+
width="12"
|
|
937
|
+
height="12"
|
|
938
|
+
viewBox="0 0 24 24"
|
|
939
|
+
fill="none"
|
|
940
|
+
stroke="currentColor"
|
|
941
|
+
strokeWidth="2"
|
|
942
|
+
strokeLinecap="round"
|
|
943
|
+
strokeLinejoin="round"
|
|
944
|
+
>
|
|
945
|
+
<circle cx="12" cy="7" r="4" />
|
|
946
|
+
<path d="M5.5 21a6.5 6.5 0 0 1 13 0Z" />
|
|
947
|
+
</svg>
|
|
948
|
+
Local Deploy
|
|
949
|
+
</>
|
|
950
|
+
)}
|
|
951
|
+
<span style={{ fontSize: '8px' }}>
|
|
952
|
+
{deploymentsDropdownOpen ? '▲' : '▼'}
|
|
953
|
+
</span>
|
|
789
954
|
</button>
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
955
|
+
|
|
956
|
+
{deploymentsDropdownOpen && (
|
|
957
|
+
<div
|
|
958
|
+
style={{
|
|
959
|
+
position: 'absolute',
|
|
960
|
+
top: '100%',
|
|
961
|
+
left: 0,
|
|
962
|
+
marginTop: '4px',
|
|
963
|
+
padding: '12px',
|
|
964
|
+
backgroundColor: 'white',
|
|
965
|
+
border: '1px solid #ddd',
|
|
966
|
+
borderRadius: '8px',
|
|
967
|
+
boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
|
|
968
|
+
zIndex: 1000,
|
|
969
|
+
minWidth: '340px',
|
|
970
|
+
}}
|
|
971
|
+
>
|
|
972
|
+
{currentNamespaceSources.primary_source?.type ===
|
|
973
|
+
'git' ? (
|
|
974
|
+
<a
|
|
975
|
+
href={
|
|
976
|
+
currentNamespaceSources.primary_source.repository?.startsWith(
|
|
977
|
+
'http',
|
|
978
|
+
)
|
|
979
|
+
? currentNamespaceSources.primary_source
|
|
980
|
+
.repository
|
|
981
|
+
: `https://${currentNamespaceSources.primary_source.repository}`
|
|
982
|
+
}
|
|
983
|
+
target="_blank"
|
|
984
|
+
rel="noopener noreferrer"
|
|
985
|
+
style={{
|
|
986
|
+
display: 'flex',
|
|
987
|
+
alignItems: 'center',
|
|
988
|
+
gap: '8px',
|
|
989
|
+
fontSize: '13px',
|
|
990
|
+
fontWeight: 400,
|
|
991
|
+
textDecoration: 'none',
|
|
992
|
+
marginBottom: '12px',
|
|
993
|
+
}}
|
|
994
|
+
>
|
|
995
|
+
<svg
|
|
996
|
+
width="16"
|
|
997
|
+
height="16"
|
|
998
|
+
viewBox="0 0 24 24"
|
|
999
|
+
fill="none"
|
|
1000
|
+
stroke="currentColor"
|
|
1001
|
+
strokeWidth="2"
|
|
1002
|
+
strokeLinecap="round"
|
|
1003
|
+
strokeLinejoin="round"
|
|
1004
|
+
>
|
|
1005
|
+
<line x1="6" y1="3" x2="6" y2="15" />
|
|
1006
|
+
<circle cx="18" cy="6" r="3" />
|
|
1007
|
+
<circle cx="6" cy="18" r="3" />
|
|
1008
|
+
<path d="M18 9a9 9 0 0 1-9 9" />
|
|
1009
|
+
</svg>
|
|
1010
|
+
{
|
|
1011
|
+
currentNamespaceSources.primary_source
|
|
1012
|
+
.repository
|
|
1013
|
+
}
|
|
1014
|
+
{currentNamespaceSources.primary_source
|
|
1015
|
+
.branch &&
|
|
1016
|
+
` (${currentNamespaceSources.primary_source.branch})`}
|
|
1017
|
+
</a>
|
|
1018
|
+
) : (
|
|
1019
|
+
<div
|
|
1020
|
+
style={{
|
|
1021
|
+
display: 'flex',
|
|
1022
|
+
alignItems: 'center',
|
|
1023
|
+
gap: '8px',
|
|
1024
|
+
fontSize: '13px',
|
|
1025
|
+
fontWeight: 600,
|
|
1026
|
+
color: '#0b3d91',
|
|
1027
|
+
marginBottom: '12px',
|
|
1028
|
+
}}
|
|
1029
|
+
>
|
|
1030
|
+
<svg
|
|
1031
|
+
width="16"
|
|
1032
|
+
height="16"
|
|
1033
|
+
viewBox="0 0 24 24"
|
|
1034
|
+
fill="none"
|
|
1035
|
+
stroke="currentColor"
|
|
1036
|
+
strokeWidth="2"
|
|
1037
|
+
strokeLinecap="round"
|
|
1038
|
+
strokeLinejoin="round"
|
|
1039
|
+
>
|
|
1040
|
+
<circle cx="12" cy="7" r="4" />
|
|
1041
|
+
<path d="M5.5 21a6.5 6.5 0 0 1 13 0Z" />
|
|
1042
|
+
</svg>
|
|
1043
|
+
{recentDeployments?.[0]?.created_by
|
|
1044
|
+
? `Local deploys by ${recentDeployments[0].created_by}`
|
|
1045
|
+
: 'Local/adhoc deployments'}
|
|
1046
|
+
</div>
|
|
1047
|
+
)}
|
|
1048
|
+
|
|
1049
|
+
{/* Separator */}
|
|
1050
|
+
<div
|
|
1051
|
+
style={{
|
|
1052
|
+
height: '1px',
|
|
1053
|
+
backgroundColor: '#e2e8f0',
|
|
1054
|
+
marginBottom: '8px',
|
|
1055
|
+
}}
|
|
1056
|
+
/>
|
|
1057
|
+
|
|
1058
|
+
{/* Recent deployments list (no header) */}
|
|
1059
|
+
{recentDeployments?.length > 0 ? (
|
|
1060
|
+
recentDeployments.map((d, idx) => {
|
|
1061
|
+
const isGit = d.source?.type === 'git';
|
|
1062
|
+
const statusColor =
|
|
1063
|
+
d.status === 'success'
|
|
1064
|
+
? '#22c55e'
|
|
1065
|
+
: d.status === 'failed'
|
|
1066
|
+
? '#ef4444'
|
|
1067
|
+
: '#94a3b8';
|
|
1068
|
+
|
|
1069
|
+
// Build commit URL if available
|
|
1070
|
+
const commitUrl =
|
|
1071
|
+
isGit &&
|
|
1072
|
+
d.source?.repository &&
|
|
1073
|
+
d.source?.commit_sha
|
|
1074
|
+
? `${
|
|
1075
|
+
d.source.repository.startsWith('http')
|
|
1076
|
+
? d.source.repository
|
|
1077
|
+
: `https://${d.source.repository}`
|
|
1078
|
+
}/commit/${d.source.commit_sha}`
|
|
1079
|
+
: null;
|
|
1080
|
+
|
|
1081
|
+
// For git: show branch + short SHA; for local: reason or hostname
|
|
1082
|
+
const detail = isGit
|
|
1083
|
+
? d.source?.branch || 'main'
|
|
1084
|
+
: d.source?.reason ||
|
|
1085
|
+
d.source?.hostname ||
|
|
1086
|
+
'adhoc';
|
|
1087
|
+
|
|
1088
|
+
const shortSha = d.source?.commit_sha?.slice(
|
|
1089
|
+
0,
|
|
1090
|
+
7,
|
|
1091
|
+
);
|
|
1092
|
+
|
|
1093
|
+
return (
|
|
1094
|
+
<div
|
|
1095
|
+
key={`${d.uuid}-${idx}`}
|
|
1096
|
+
style={{
|
|
1097
|
+
display: 'grid',
|
|
1098
|
+
gridTemplateColumns: '18px 1fr auto auto',
|
|
1099
|
+
alignItems: 'center',
|
|
1100
|
+
gap: '8px',
|
|
1101
|
+
padding: '6px 0',
|
|
1102
|
+
borderBottom:
|
|
1103
|
+
idx === recentDeployments.length - 1
|
|
1104
|
+
? 'none'
|
|
1105
|
+
: '1px solid #f1f5f9',
|
|
1106
|
+
fontSize: '12px',
|
|
1107
|
+
}}
|
|
1108
|
+
>
|
|
1109
|
+
{/* Status dot */}
|
|
1110
|
+
<div
|
|
1111
|
+
style={{
|
|
1112
|
+
width: '8px',
|
|
1113
|
+
height: '8px',
|
|
1114
|
+
borderRadius: '50%',
|
|
1115
|
+
backgroundColor: statusColor,
|
|
1116
|
+
}}
|
|
1117
|
+
title={d.status}
|
|
1118
|
+
/>
|
|
1119
|
+
|
|
1120
|
+
{/* User + detail */}
|
|
1121
|
+
<div
|
|
1122
|
+
style={{
|
|
1123
|
+
display: 'flex',
|
|
1124
|
+
alignItems: 'center',
|
|
1125
|
+
gap: '6px',
|
|
1126
|
+
minWidth: 0,
|
|
1127
|
+
}}
|
|
1128
|
+
>
|
|
1129
|
+
<span
|
|
1130
|
+
style={{
|
|
1131
|
+
fontWeight: 500,
|
|
1132
|
+
color: '#0f172a',
|
|
1133
|
+
whiteSpace: 'nowrap',
|
|
1134
|
+
}}
|
|
1135
|
+
>
|
|
1136
|
+
{d.created_by || 'unknown'}
|
|
1137
|
+
</span>
|
|
1138
|
+
<span style={{ color: '#cbd5e1' }}>
|
|
1139
|
+
—
|
|
1140
|
+
</span>
|
|
1141
|
+
{isGit ? (
|
|
1142
|
+
<>
|
|
1143
|
+
<span
|
|
1144
|
+
style={{
|
|
1145
|
+
color: '#64748b',
|
|
1146
|
+
whiteSpace: 'nowrap',
|
|
1147
|
+
}}
|
|
1148
|
+
>
|
|
1149
|
+
{detail}
|
|
1150
|
+
</span>
|
|
1151
|
+
{shortSha && (
|
|
1152
|
+
<>
|
|
1153
|
+
<span
|
|
1154
|
+
style={{ color: '#cbd5e1' }}
|
|
1155
|
+
>
|
|
1156
|
+
@
|
|
1157
|
+
</span>
|
|
1158
|
+
{commitUrl ? (
|
|
1159
|
+
<a
|
|
1160
|
+
href={commitUrl}
|
|
1161
|
+
target="_blank"
|
|
1162
|
+
rel="noopener noreferrer"
|
|
1163
|
+
style={{
|
|
1164
|
+
fontFamily: 'monospace',
|
|
1165
|
+
fontSize: '11px',
|
|
1166
|
+
color: '#3b82f6',
|
|
1167
|
+
textDecoration: 'none',
|
|
1168
|
+
}}
|
|
1169
|
+
>
|
|
1170
|
+
{shortSha}
|
|
1171
|
+
</a>
|
|
1172
|
+
) : (
|
|
1173
|
+
<span
|
|
1174
|
+
style={{
|
|
1175
|
+
fontFamily: 'monospace',
|
|
1176
|
+
fontSize: '11px',
|
|
1177
|
+
color: '#64748b',
|
|
1178
|
+
}}
|
|
1179
|
+
>
|
|
1180
|
+
{shortSha}
|
|
1181
|
+
</span>
|
|
1182
|
+
)}
|
|
1183
|
+
</>
|
|
1184
|
+
)}
|
|
1185
|
+
</>
|
|
1186
|
+
) : (
|
|
1187
|
+
<span
|
|
1188
|
+
style={{
|
|
1189
|
+
color: '#64748b',
|
|
1190
|
+
overflow: 'hidden',
|
|
1191
|
+
textOverflow: 'ellipsis',
|
|
1192
|
+
whiteSpace: 'nowrap',
|
|
1193
|
+
}}
|
|
1194
|
+
>
|
|
1195
|
+
{detail}
|
|
1196
|
+
</span>
|
|
1197
|
+
)}
|
|
1198
|
+
</div>
|
|
1199
|
+
|
|
1200
|
+
{/* Timestamp */}
|
|
1201
|
+
<span
|
|
1202
|
+
style={{
|
|
1203
|
+
color: '#94a3b8',
|
|
1204
|
+
fontSize: '11px',
|
|
1205
|
+
whiteSpace: 'nowrap',
|
|
1206
|
+
}}
|
|
1207
|
+
>
|
|
1208
|
+
{new Date(
|
|
1209
|
+
d.created_at,
|
|
1210
|
+
).toLocaleDateString()}
|
|
1211
|
+
</span>
|
|
1212
|
+
|
|
1213
|
+
{/* Icon */}
|
|
1214
|
+
<div
|
|
1215
|
+
style={{
|
|
1216
|
+
color: isGit ? '#155724' : '#0b3d91',
|
|
1217
|
+
}}
|
|
1218
|
+
>
|
|
1219
|
+
{isGit ? (
|
|
1220
|
+
<svg
|
|
1221
|
+
width="12"
|
|
1222
|
+
height="12"
|
|
1223
|
+
viewBox="0 0 24 24"
|
|
1224
|
+
fill="none"
|
|
1225
|
+
stroke="currentColor"
|
|
1226
|
+
strokeWidth="2"
|
|
1227
|
+
strokeLinecap="round"
|
|
1228
|
+
strokeLinejoin="round"
|
|
1229
|
+
>
|
|
1230
|
+
<line x1="6" y1="3" x2="6" y2="15" />
|
|
1231
|
+
<circle cx="18" cy="6" r="3" />
|
|
1232
|
+
<circle cx="6" cy="18" r="3" />
|
|
1233
|
+
<path d="M18 9a9 9 0 0 1-9 9" />
|
|
1234
|
+
</svg>
|
|
1235
|
+
) : (
|
|
1236
|
+
<svg
|
|
1237
|
+
width="12"
|
|
1238
|
+
height="12"
|
|
1239
|
+
viewBox="0 0 24 24"
|
|
1240
|
+
fill="none"
|
|
1241
|
+
stroke="currentColor"
|
|
1242
|
+
strokeWidth="2"
|
|
1243
|
+
strokeLinecap="round"
|
|
1244
|
+
strokeLinejoin="round"
|
|
1245
|
+
>
|
|
1246
|
+
<circle cx="12" cy="7" r="4" />
|
|
1247
|
+
<path d="M5.5 21a6.5 6.5 0 0 1 13 0Z" />
|
|
1248
|
+
</svg>
|
|
1249
|
+
)}
|
|
1250
|
+
</div>
|
|
1251
|
+
</div>
|
|
1252
|
+
);
|
|
1253
|
+
})
|
|
1254
|
+
) : (
|
|
1255
|
+
<div
|
|
1256
|
+
style={{
|
|
1257
|
+
color: '#94a3b8',
|
|
1258
|
+
fontSize: '12px',
|
|
1259
|
+
textAlign: 'center',
|
|
1260
|
+
padding: '8px 0',
|
|
1261
|
+
}}
|
|
1262
|
+
>
|
|
1263
|
+
No deployments yet
|
|
1264
|
+
</div>
|
|
1265
|
+
)}
|
|
1266
|
+
</div>
|
|
1267
|
+
)}
|
|
1268
|
+
</div>
|
|
816
1269
|
)}
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
1270
|
+
</div>
|
|
1271
|
+
<div
|
|
1272
|
+
style={{ display: 'flex', alignItems: 'center', gap: '8px' }}
|
|
1273
|
+
>
|
|
1274
|
+
<a
|
|
1275
|
+
href={`${getDJUrl()}/namespaces/${namespace}/export/yaml`}
|
|
1276
|
+
download
|
|
1277
|
+
style={{
|
|
1278
|
+
display: 'inline-flex',
|
|
1279
|
+
alignItems: 'center',
|
|
1280
|
+
gap: '4px',
|
|
1281
|
+
// padding: '6px 12px',
|
|
1282
|
+
fontSize: '13px',
|
|
1283
|
+
fontWeight: '500',
|
|
1284
|
+
color: '#475569',
|
|
1285
|
+
// backgroundColor: '#f8fafc',
|
|
1286
|
+
// border: '1px solid #e2e8f0',
|
|
1287
|
+
borderRadius: '6px',
|
|
1288
|
+
textDecoration: 'none',
|
|
1289
|
+
cursor: 'pointer',
|
|
1290
|
+
transition: 'all 0.15s ease',
|
|
1291
|
+
margin: '0.5em 0px 0px 1em',
|
|
1292
|
+
}}
|
|
1293
|
+
onMouseOver={e => {
|
|
1294
|
+
e.currentTarget.style.color = '#333333';
|
|
1295
|
+
}}
|
|
1296
|
+
onMouseOut={e => {
|
|
1297
|
+
e.currentTarget.style.color = '#475569';
|
|
1298
|
+
}}
|
|
1299
|
+
title="Export namespace to YAML"
|
|
1300
|
+
>
|
|
1301
|
+
<svg
|
|
1302
|
+
width="14"
|
|
1303
|
+
height="14"
|
|
1304
|
+
viewBox="0 0 24 24"
|
|
1305
|
+
fill="none"
|
|
1306
|
+
stroke="currentColor"
|
|
1307
|
+
strokeWidth="2"
|
|
1308
|
+
strokeLinecap="round"
|
|
1309
|
+
strokeLinejoin="round"
|
|
1310
|
+
>
|
|
1311
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
1312
|
+
<polyline points="7 10 12 15 17 10"></polyline>
|
|
1313
|
+
<line x1="12" y1="15" x2="12" y2="3"></line>
|
|
1314
|
+
</svg>
|
|
1315
|
+
</a>
|
|
1316
|
+
<AddNodeDropdown namespace={namespace} />
|
|
1317
|
+
</div>
|
|
1318
|
+
</div>
|
|
1319
|
+
<table className="card-table table" style={{ marginBottom: 0 }}>
|
|
1320
|
+
<thead>
|
|
1321
|
+
<tr>
|
|
1322
|
+
{fields.map(field => {
|
|
1323
|
+
const thStyle = {
|
|
1324
|
+
fontFamily:
|
|
1325
|
+
"'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
|
|
1326
|
+
fontSize: '11px',
|
|
1327
|
+
fontWeight: '600',
|
|
1328
|
+
textTransform: 'uppercase',
|
|
1329
|
+
letterSpacing: '0.5px',
|
|
1330
|
+
color: '#64748b',
|
|
1331
|
+
padding: '12px 16px',
|
|
1332
|
+
borderBottom: '1px solid #e2e8f0',
|
|
1333
|
+
backgroundColor: 'transparent',
|
|
1334
|
+
};
|
|
1335
|
+
return (
|
|
1336
|
+
<th key={field} style={thStyle}>
|
|
1337
|
+
<button
|
|
1338
|
+
type="button"
|
|
1339
|
+
onClick={() => requestSort(field)}
|
|
1340
|
+
className={'sortable ' + getClassNamesFor(field)}
|
|
1341
|
+
style={{
|
|
1342
|
+
fontSize: 'inherit',
|
|
1343
|
+
fontWeight: 'inherit',
|
|
1344
|
+
letterSpacing: 'inherit',
|
|
1345
|
+
textTransform: 'inherit',
|
|
1346
|
+
fontFamily: 'inherit',
|
|
1347
|
+
}}
|
|
1348
|
+
>
|
|
1349
|
+
{field.replace(/([a-z](?=[A-Z]))/g, '$1 ')}
|
|
1350
|
+
</button>
|
|
1351
|
+
</th>
|
|
1352
|
+
);
|
|
1353
|
+
})}
|
|
1354
|
+
<th
|
|
1355
|
+
style={{
|
|
1356
|
+
fontFamily:
|
|
1357
|
+
"'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
|
|
1358
|
+
fontSize: '11px',
|
|
1359
|
+
fontWeight: '600',
|
|
1360
|
+
textTransform: 'uppercase',
|
|
1361
|
+
letterSpacing: '0.5px',
|
|
1362
|
+
color: '#64748b',
|
|
1363
|
+
padding: '12px 16px',
|
|
1364
|
+
borderBottom: '1px solid #e2e8f0',
|
|
1365
|
+
backgroundColor: 'transparent',
|
|
1366
|
+
}}
|
|
1367
|
+
>
|
|
1368
|
+
Actions
|
|
1369
|
+
</th>
|
|
1370
|
+
</tr>
|
|
1371
|
+
</thead>
|
|
1372
|
+
<tbody className="nodes-table-body">{nodesList}</tbody>
|
|
1373
|
+
<tfoot>
|
|
1374
|
+
<tr>
|
|
1375
|
+
<td>
|
|
1376
|
+
{retrieved && hasPrevPage ? (
|
|
1377
|
+
<a
|
|
1378
|
+
onClick={loadPrev}
|
|
1379
|
+
className="previous round pagination"
|
|
1380
|
+
>
|
|
1381
|
+
← Previous
|
|
1382
|
+
</a>
|
|
1383
|
+
) : (
|
|
1384
|
+
''
|
|
1385
|
+
)}
|
|
1386
|
+
{retrieved && hasNextPage ? (
|
|
1387
|
+
<a onClick={loadNext} className="next round pagination">
|
|
1388
|
+
Next →
|
|
1389
|
+
</a>
|
|
1390
|
+
) : (
|
|
1391
|
+
''
|
|
1392
|
+
)}
|
|
1393
|
+
</td>
|
|
1394
|
+
</tr>
|
|
1395
|
+
</tfoot>
|
|
1396
|
+
</table>
|
|
1397
|
+
</div>
|
|
821
1398
|
</div>
|
|
822
1399
|
</div>
|
|
823
1400
|
</div>
|