pglens 2.0.1 → 2.1.0

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/client/index.html CHANGED
@@ -146,6 +146,32 @@
146
146
  </div>
147
147
  </div>
148
148
  <div class="pagination" id="pagination" style="display: none;"></div>
149
+
150
+ <div class="landing-page" id="landingPage" style="display: none;">
151
+ <div class="landing-header-bar">
152
+ <div class="search-container">
153
+ <svg class="search-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"
154
+ stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
155
+ <circle cx="11" cy="11" r="8"></circle>
156
+ <line x1="21" y1="21" x2="16.65" y2="16.65"></line>
157
+ </svg>
158
+ <input type="text" id="connectionSearch" placeholder="Search connections by host, database name or type..."
159
+ autocomplete="off">
160
+ </div>
161
+ <button class="button-primary new-connection-btn" id="newConnectionBtn">
162
+ <span class="icon">+</span> New Connection
163
+ </button>
164
+ </div>
165
+
166
+ <div class="landing-section-header">
167
+ <h2>All Connections</h2>
168
+ <p>Manage and access your database instances.</p>
169
+ </div>
170
+
171
+ <div class="connections-grid" id="connectionsGrid">
172
+ <!-- Connection cards will be rendered here -->
173
+ </div>
174
+ </div>
149
175
  </div>
150
176
  <div class="loading-overlay" id="loadingOverlay" style="display: none;">
151
177
  <div class="loading-spinner"></div>
package/client/styles.css CHANGED
@@ -540,7 +540,19 @@ code {
540
540
  margin-right: var(--space-2);
541
541
  }
542
542
 
543
- .connection-disconnect {
543
+ .connection-actions {
544
+ display: flex;
545
+ align-items: center;
546
+ gap: 2px;
547
+ opacity: 0;
548
+ transition: opacity var(--transition-fast);
549
+ }
550
+
551
+ .connection-item:hover .connection-actions {
552
+ opacity: 1;
553
+ }
554
+
555
+ .connection-action-btn {
544
556
  background: none;
545
557
  border: none;
546
558
  cursor: pointer;
@@ -550,24 +562,23 @@ code {
550
562
  display: flex;
551
563
  align-items: center;
552
564
  justify-content: center;
553
- width: 16px;
554
- height: 16px;
565
+ width: 20px;
566
+ height: 20px;
555
567
  font-size: 14px;
556
568
  line-height: 1;
557
- opacity: 0;
558
569
  transition: all var(--transition-fast);
559
570
  }
560
571
 
561
- .connection-item:hover .connection-disconnect {
562
- opacity: 1;
572
+ .connection-action-btn:hover {
573
+ background-color: rgba(0, 0, 0, 0.05);
574
+ color: var(--text-primary);
563
575
  }
564
576
 
565
- .connection-disconnect:hover {
566
- background-color: rgba(0, 0, 0, 0.05);
577
+ .connection-action-btn.delete:hover {
567
578
  color: var(--color-error);
568
579
  }
569
580
 
570
- [data-theme="dark"] .connection-disconnect:hover {
581
+ [data-theme="dark"] .connection-action-btn:hover {
571
582
  background-color: rgba(255, 255, 255, 0.1);
572
583
  }
573
584
 
@@ -863,6 +874,319 @@ code {
863
874
  transform: scale(0.98);
864
875
  }
865
876
 
877
+ .tab-server-badge {
878
+ font-size: 10px;
879
+ background-color: var(--bg-elevated);
880
+ border: 1px solid var(--border-subtle);
881
+ color: var(--text-secondary);
882
+ padding: 1px 4px;
883
+ border-radius: 3px;
884
+ margin-right: 6px;
885
+ font-weight: var(--font-weight-medium);
886
+ white-space: nowrap;
887
+ text-transform: uppercase;
888
+ letter-spacing: 0.05em;
889
+ }
890
+
891
+ [data-theme="dark"] .tab-server-badge {
892
+ background-color: var(--bg-hover);
893
+ color: var(--text-tertiary);
894
+ }
895
+
896
+ /* Landing Page */
897
+ .landing-page {
898
+ flex: 1;
899
+ display: flex;
900
+ flex-direction: column;
901
+ padding: var(--space-8);
902
+ background-color: var(--bg-base);
903
+ height: 100%;
904
+ overflow-y: auto;
905
+ }
906
+
907
+ .landing-header-bar {
908
+ display: flex;
909
+ align-items: center;
910
+ justify-content: space-between;
911
+ margin-bottom: var(--space-8);
912
+ gap: var(--space-4);
913
+ }
914
+
915
+ .search-container {
916
+ flex: 1;
917
+ max-width: 600px;
918
+ position: relative;
919
+ display: flex;
920
+ align-items: center;
921
+ }
922
+
923
+ .search-container .search-icon {
924
+ position: absolute;
925
+ left: var(--space-3);
926
+ color: var(--text-tertiary);
927
+ pointer-events: none;
928
+ }
929
+
930
+ #connectionSearch {
931
+ width: 100%;
932
+ padding: var(--space-3) var(--space-4);
933
+ padding-left: var(--space-10);
934
+ background-color: var(--bg-elevated);
935
+ border: 1px solid var(--border-subtle);
936
+ border-radius: var(--radius-md);
937
+ color: var(--text-primary);
938
+ font-size: var(--font-size-sm);
939
+ transition: all var(--transition-fast);
940
+ }
941
+
942
+ #connectionSearch:focus {
943
+ outline: none;
944
+ border-color: var(--color-primary);
945
+ box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
946
+ }
947
+
948
+ .new-connection-btn {
949
+ display: flex;
950
+ align-items: center;
951
+ gap: var(--space-2);
952
+ padding: var(--space-2) var(--space-4);
953
+ font-weight: var(--font-weight-medium);
954
+ height: 40px;
955
+ }
956
+
957
+ .landing-section-header {
958
+ margin-bottom: var(--space-6);
959
+ }
960
+
961
+ .landing-section-header h2 {
962
+ font-size: 1.5rem;
963
+ font-weight: var(--font-weight-bold);
964
+ color: var(--text-primary);
965
+ margin-bottom: var(--space-1);
966
+ }
967
+
968
+ .landing-section-header p {
969
+ color: var(--text-secondary);
970
+ font-size: var(--font-size-sm);
971
+ }
972
+
973
+ .connections-grid {
974
+ display: grid;
975
+ grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
976
+ gap: var(--space-6);
977
+ width: 100%;
978
+ }
979
+
980
+ .connection-card {
981
+ background-color: var(--bg-elevated);
982
+ border: 1px solid var(--border-subtle);
983
+ border-radius: var(--radius-lg);
984
+ padding: var(--space-6);
985
+ transition: all var(--transition-base);
986
+ display: flex;
987
+ flex-direction: column;
988
+ position: relative;
989
+ min-height: 200px;
990
+ }
991
+
992
+ .connection-card:hover {
993
+ transform: translateY(-2px);
994
+ border-color: var(--border-default);
995
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
996
+ }
997
+
998
+ .card-top {
999
+ display: flex;
1000
+ justify-content: space-between;
1001
+ align-items: flex-start;
1002
+ margin-bottom: var(--space-6);
1003
+ }
1004
+
1005
+ .card-icon {
1006
+ width: 40px;
1007
+ height: 40px;
1008
+ background-color: var(--bg-hover);
1009
+ border-radius: var(--radius-md);
1010
+ display: flex;
1011
+ align-items: center;
1012
+ justify-content: center;
1013
+ color: var(--color-primary);
1014
+ }
1015
+
1016
+ .card-status {
1017
+ display: flex;
1018
+ align-items: center;
1019
+ gap: var(--space-2);
1020
+ padding: 4px 8px;
1021
+ background-color: rgba(16, 185, 129, 0.1);
1022
+ color: #10b981;
1023
+ border-radius: var(--radius-full);
1024
+ font-size: 11px;
1025
+ font-weight: var(--font-weight-medium);
1026
+ text-transform: uppercase;
1027
+ }
1028
+
1029
+ [data-theme="dark"] .card-status {
1030
+ background-color: rgba(16, 185, 129, 0.2);
1031
+ }
1032
+
1033
+ .card-status-dot {
1034
+ width: 6px;
1035
+ height: 6px;
1036
+ background-color: currentColor;
1037
+ border-radius: 50%;
1038
+ }
1039
+
1040
+ .card-info h3 {
1041
+ font-size: var(--font-size-lg);
1042
+ font-weight: var(--font-weight-bold);
1043
+ color: var(--text-primary);
1044
+ margin-bottom: var(--space-1);
1045
+ }
1046
+
1047
+ .card-info p {
1048
+ color: var(--text-secondary);
1049
+ font-size: var(--font-size-sm);
1050
+ margin-bottom: var(--space-4);
1051
+ }
1052
+
1053
+ .host-block {
1054
+ background-color: var(--bg-base);
1055
+ border-radius: var(--radius-md);
1056
+ padding: var(--space-3);
1057
+ margin-bottom: var(--space-6);
1058
+ }
1059
+
1060
+ .host-label {
1061
+ display: block;
1062
+ font-size: 10px;
1063
+ font-weight: var(--font-weight-bold);
1064
+ color: var(--text-tertiary);
1065
+ margin-bottom: var(--space-1);
1066
+ letter-spacing: 0.05em;
1067
+ text-transform: uppercase;
1068
+ }
1069
+
1070
+ .host-value {
1071
+ font-family: var(--font-mono);
1072
+ font-size: var(--font-size-sm);
1073
+ color: var(--text-secondary);
1074
+ }
1075
+
1076
+ .card-actions-wrapper {
1077
+ margin-top: auto;
1078
+ display: flex;
1079
+ gap: var(--space-3);
1080
+ }
1081
+
1082
+ .connect-btn {
1083
+ flex: 1;
1084
+ display: flex;
1085
+ align-items: center;
1086
+ justify-content: center;
1087
+ gap: var(--space-2);
1088
+ padding: var(--space-3);
1089
+ background-color: transparent;
1090
+ border: 1px solid var(--border-subtle);
1091
+ border-radius: var(--radius-md);
1092
+ color: var(--text-primary);
1093
+ font-weight: var(--font-weight-medium);
1094
+ cursor: pointer;
1095
+ transition: all var(--transition-fast);
1096
+ }
1097
+
1098
+ .connect-btn:hover {
1099
+ background-color: var(--bg-hover);
1100
+ border-color: var(--border-default);
1101
+ }
1102
+
1103
+ /* Add New Card specific styles */
1104
+ .connection-card.add-new-card {
1105
+ border: 2px dashed var(--border-subtle);
1106
+ align-items: center;
1107
+ justify-content: center;
1108
+ gap: var(--space-4);
1109
+ background-color: transparent;
1110
+ cursor: pointer;
1111
+ }
1112
+
1113
+ .connection-card.add-new-card:hover {
1114
+ border-color: var(--color-primary);
1115
+ background-color: var(--bg-hover);
1116
+ }
1117
+
1118
+ .add-new-icon-circle {
1119
+ width: 48px;
1120
+ height: 48px;
1121
+ border-radius: 50%;
1122
+ background-color: var(--bg-elevated);
1123
+ display: flex;
1124
+ align-items: center;
1125
+ justify-content: center;
1126
+ font-size: 24px;
1127
+ color: var(--text-secondary);
1128
+ transition: all var(--transition-fast);
1129
+ }
1130
+
1131
+ .connection-card.add-new-card:hover .add-new-icon-circle {
1132
+ background-color: var(--color-primary);
1133
+ color: white;
1134
+ }
1135
+
1136
+ .add-new-text {
1137
+ font-size: var(--font-size-lg);
1138
+ font-weight: var(--font-weight-medium);
1139
+ color: var(--text-secondary);
1140
+ }
1141
+
1142
+ .connection-card.add-new-card:hover .add-new-text {
1143
+ color: var(--text-primary);
1144
+ }
1145
+
1146
+ .connection-card.add-new-card .add-desc {
1147
+ color: var(--text-tertiary);
1148
+ font-size: var(--font-size-sm);
1149
+ }
1150
+
1151
+ /* Context menu style actions for edit/delete */
1152
+ .card-context-actions {
1153
+ position: absolute;
1154
+ top: var(--space-4);
1155
+ right: var(--space-4);
1156
+ opacity: 0;
1157
+ transition: opacity var(--transition-fast);
1158
+ display: flex;
1159
+ gap: var(--space-2);
1160
+ }
1161
+
1162
+ .connection-card:hover .card-context-actions {
1163
+ opacity: 1;
1164
+ }
1165
+
1166
+ .context-btn {
1167
+ width: 28px;
1168
+ height: 28px;
1169
+ border-radius: var(--radius-md);
1170
+ border: none;
1171
+ background-color: var(--bg-hover);
1172
+ color: var(--text-secondary);
1173
+ display: flex;
1174
+ align-items: center;
1175
+ justify-content: center;
1176
+ cursor: pointer;
1177
+ transition: all var(--transition-fast);
1178
+ }
1179
+
1180
+ .context-btn:hover {
1181
+ background-color: var(--bg-active);
1182
+ color: var(--text-primary);
1183
+ }
1184
+
1185
+ .context-btn.delete:hover {
1186
+ color: var(--color-error);
1187
+ background-color: rgba(239, 68, 68, 0.1);
1188
+ }
1189
+
866
1190
  .refresh-icon {
867
1191
  width: 16px;
868
1192
  height: 16px;
@@ -1003,7 +1327,6 @@ code {
1003
1327
  .table-container {
1004
1328
  flex: 1;
1005
1329
  overflow: auto;
1006
- padding: var(--space-6);
1007
1330
  }
1008
1331
 
1009
1332
  table {
@@ -1014,13 +1337,6 @@ table {
1014
1337
  table-layout: auto;
1015
1338
  }
1016
1339
 
1017
- thead {
1018
- background-color: var(--bg-elevated);
1019
- position: sticky;
1020
- top: 0;
1021
- z-index: 10;
1022
- }
1023
-
1024
1340
  th {
1025
1341
  padding: var(--space-3) var(--space-4);
1026
1342
  text-align: left;
@@ -1030,7 +1346,10 @@ th {
1030
1346
  white-space: normal;
1031
1347
  font-size: var(--font-size-xs);
1032
1348
  letter-spacing: 0.05em;
1033
- position: relative;
1349
+ position: sticky;
1350
+ top: 0;
1351
+ z-index: 10;
1352
+ background-color: var(--bg-elevated);
1034
1353
  vertical-align: bottom;
1035
1354
  }
1036
1355
 
@@ -1729,4 +2048,188 @@ html[data-theme="dark"] .loading-overlay {
1729
2048
  100% {
1730
2049
  transform: rotate(360deg);
1731
2050
  }
2051
+ }
2052
+
2053
+ /* Shimmer Loading */
2054
+ .skeleton {
2055
+ background: linear-gradient(90deg,
2056
+ var(--bg-elevated) 25%,
2057
+ var(--bg-hover) 37%,
2058
+ var(--bg-elevated) 63%);
2059
+ background-size: 400% 100%;
2060
+ animation: shimmer 1.4s ease infinite;
2061
+ border-radius: var(--radius-sm);
2062
+ height: 20px;
2063
+ width: 100%;
2064
+ }
2065
+
2066
+ @keyframes shimmer {
2067
+ 0% {
2068
+ background-position: 100% 50%;
2069
+ }
2070
+
2071
+ 100% {
2072
+ background-position: 0 50%;
2073
+ }
2074
+ }
2075
+
2076
+ .shimmer-row td {
2077
+ padding: var(--space-3) var(--space-4);
2078
+ border-bottom: 1px solid var(--border-subtle);
2079
+ }
2080
+
2081
+ .shimmer-cell {
2082
+ height: 20px;
2083
+ }
2084
+
2085
+ /* Cancel Button */
2086
+ .cancel-button {
2087
+ display: flex;
2088
+ align-items: center;
2089
+ gap: var(--space-2);
2090
+ padding: var(--space-2) var(--space-3);
2091
+ background-color: var(--bg-elevated);
2092
+ border: 1px solid var(--color-error);
2093
+ border-radius: var(--radius-md);
2094
+ color: var(--color-error);
2095
+ font-size: var(--font-size-sm);
2096
+ font-weight: var(--font-weight-medium);
2097
+ cursor: pointer;
2098
+ transition: all var(--transition-fast);
2099
+ }
2100
+
2101
+ .cancel-button:hover {
2102
+ background-color: rgba(239, 68, 68, 0.1);
2103
+ }
2104
+
2105
+ .cancel-button:active {
2106
+ transform: scale(0.98);
2107
+ }
2108
+
2109
+ /* Table Dashboard */
2110
+ .table-dashboard {
2111
+ padding: var(--space-8);
2112
+ height: 100%;
2113
+ overflow-y: auto;
2114
+ display: flex;
2115
+ flex-direction: column;
2116
+ }
2117
+
2118
+ .table-dashboard-header {
2119
+ margin-bottom: var(--space-6);
2120
+ }
2121
+
2122
+ .table-dashboard-header h2 {
2123
+ font-size: 1.5rem;
2124
+ font-weight: var(--font-weight-bold);
2125
+ color: var(--text-primary);
2126
+ margin-bottom: var(--space-1);
2127
+ }
2128
+
2129
+ .table-dashboard-header p {
2130
+ color: var(--text-secondary);
2131
+ font-size: var(--font-size-sm);
2132
+ }
2133
+
2134
+ .tables-grid {
2135
+ display: grid;
2136
+ grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
2137
+ gap: var(--space-4);
2138
+ }
2139
+
2140
+ .table-card {
2141
+ background-color: var(--bg-elevated);
2142
+ border: 1px solid var(--border-subtle);
2143
+ border-radius: var(--radius-md);
2144
+ padding: var(--space-4);
2145
+ cursor: pointer;
2146
+ transition: all var(--transition-fast);
2147
+ display: flex;
2148
+ align-items: center;
2149
+ gap: var(--space-3);
2150
+ }
2151
+
2152
+ .table-card:hover {
2153
+ border-color: var(--color-primary);
2154
+ background-color: var(--bg-hover);
2155
+ transform: translateY(-1px);
2156
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
2157
+ }
2158
+
2159
+ .table-card-icon {
2160
+ width: 32px;
2161
+ height: 32px;
2162
+ background-color: var(--bg-base);
2163
+ border-radius: var(--radius-md);
2164
+ display: flex;
2165
+ align-items: center;
2166
+ justify-content: center;
2167
+ color: var(--text-secondary);
2168
+ }
2169
+
2170
+ .table-card:hover .table-card-icon {
2171
+ color: var(--color-primary);
2172
+ }
2173
+
2174
+ .table-card-info {
2175
+ flex: 1;
2176
+ min-width: 0;
2177
+ }
2178
+
2179
+ .table-card-name {
2180
+ font-weight: var(--font-weight-medium);
2181
+ color: var(--text-primary);
2182
+ white-space: nowrap;
2183
+ overflow: hidden;
2184
+ text-overflow: ellipsis;
2185
+ margin-bottom: 2px;
2186
+ }
2187
+
2188
+ .table-card-schema {
2189
+ font-size: 11px;
2190
+ color: var(--text-tertiary);
2191
+ text-transform: uppercase;
2192
+ letter-spacing: 0.05em;
2193
+ }
2194
+
2195
+ /* Skeleton Table Card */
2196
+ .table-card.skeleton-card {
2197
+ pointer-events: none;
2198
+ cursor: default;
2199
+ border-color: transparent;
2200
+ }
2201
+
2202
+ .table-card.skeleton-card:hover {
2203
+ transform: none;
2204
+ background-color: var(--bg-elevated);
2205
+ box-shadow: none;
2206
+ }
2207
+
2208
+ .skeleton-icon {
2209
+ width: 32px;
2210
+ height: 32px;
2211
+ border-radius: var(--radius-md);
2212
+ background: linear-gradient(90deg,
2213
+ var(--bg-hover) 25%,
2214
+ var(--bg-active) 37%,
2215
+ var(--bg-hover) 63%);
2216
+ background-size: 400% 100%;
2217
+ animation: shimmer 1.4s ease infinite;
2218
+ }
2219
+
2220
+ .skeleton-text {
2221
+ height: 14px;
2222
+ border-radius: var(--radius-sm);
2223
+ background: linear-gradient(90deg,
2224
+ var(--bg-hover) 25%,
2225
+ var(--bg-active) 37%,
2226
+ var(--bg-hover) 63%);
2227
+ background-size: 400% 100%;
2228
+ animation: shimmer 1.4s ease infinite;
2229
+ margin-bottom: 4px;
2230
+ }
2231
+
2232
+ .skeleton-text.short {
2233
+ width: 60%;
2234
+ height: 10px;
1732
2235
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pglens",
3
- "version": "2.0.1",
3
+ "version": "2.1.0",
4
4
  "description": "A simple PostgreSQL database viewer tool",
5
5
  "main": "src/server.js",
6
6
  "bin": {
@@ -31,4 +31,4 @@
31
31
  "express": "^4.18.2",
32
32
  "postgres": "^3.4.3"
33
33
  }
34
- }
34
+ }