k96beni commited on
Commit
1a170e3
·
verified ·
1 Parent(s): 6c1a6a3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +267 -7
app.py CHANGED
@@ -1110,6 +1110,60 @@ def batch_update_cells_with_tracking(sheet, changes, df, editor_email, log_sheet
1110
  else:
1111
  return False, f"❌ Fel vid sparande: {error_msg}. Kontakta migration@chargenode.eu om problemet kvarstår."
1112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1113
  def get_column_config(df):
1114
  """Generera kolumnkonfiguration för data_editor med beskrivningar och dropdowns"""
1115
  config = {}
@@ -1210,13 +1264,15 @@ st.markdown("""
1210
  }
1211
 
1212
  /* Röd triangel-indikator för editerbara kolumner */
1213
- /* Lägger till en röd triangel i övre högra hörnet av editerbara kolumnrubriker */
1214
- [data-testid="stDataFrame"] thead th:not([aria-label*="🔒"]) {
1215
  position: relative;
1216
- background-color: #FFF9F0 !important;
 
 
1217
  }
1218
 
1219
- [data-testid="stDataFrame"] thead th:not([aria-label*="🔒"])::after {
1220
  content: "";
1221
  position: absolute;
1222
  top: 0;
@@ -1229,9 +1285,52 @@ st.markdown("""
1229
  z-index: 10;
1230
  }
1231
 
1232
- /* Hover-effekt för editerbara kolumner */
1233
- [data-testid="stDataFrame"] thead th:not([aria-label*="🔒"]):hover {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1234
  background-color: #FFF3E0 !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1235
  }
1236
 
1237
  .excel-info-box {
@@ -1882,10 +1981,162 @@ else:
1882
 
1883
  **Kontrollera att uppgifterna i låsta celler stämmer.** Om något verkar fel, mejla till [migration@chargenode.eu](mailto:migration@chargenode.eu) så hjälper vi dig.
1884
  """)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1885
  st.markdown("<br>", unsafe_allow_html=True)
1886
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1887
  # Ta bort dolda kolumner och sätt kolumnordning med Fastighetsnamn först
1888
- company_areas_display = company_areas.drop(columns=HIDDEN_COLUMNS, errors='ignore')
1889
 
1890
  # Skapa kolumnordning med Fastighetsnamn först (för bättre synlighet vid scrolling)
1891
  column_order = ['Fastighetsnamn'] + [col for col in company_areas_display.columns if col != 'Fastighetsnamn']
@@ -1893,6 +2144,15 @@ else:
1893
 
1894
  column_config = get_column_config(company_areas_display)
1895
 
 
 
 
 
 
 
 
 
 
1896
  # Container för att förhindra scroll-hopp
1897
  table_container = st.container()
1898
 
 
1110
  else:
1111
  return False, f"❌ Fel vid sparande: {error_msg}. Kontakta migration@chargenode.eu om problemet kvarstår."
1112
 
1113
+ def calculate_completion_stats(df, editable_cols):
1114
+ """Beräkna kompletteringsstatistik för editerbara kolumner"""
1115
+ stats = {}
1116
+
1117
+ for col in editable_cols:
1118
+ if col in df.columns:
1119
+ total = len(df)
1120
+ # Räkna celler som har värde (inte nan, inte tom sträng)
1121
+ filled = df[col].apply(lambda x: bool(x and str(x).strip() != '')).sum()
1122
+ stats[col] = {
1123
+ 'filled': filled,
1124
+ 'total': total,
1125
+ 'percentage': (filled / total * 100) if total > 0 else 0
1126
+ }
1127
+
1128
+ # Totala stats
1129
+ total_cells = sum(s['total'] for s in stats.values())
1130
+ total_filled = sum(s['filled'] for s in stats.values())
1131
+ overall_percentage = (total_filled / total_cells * 100) if total_cells > 0 else 0
1132
+
1133
+ return {
1134
+ 'by_column': stats,
1135
+ 'overall': {
1136
+ 'filled': total_filled,
1137
+ 'total': total_cells,
1138
+ 'percentage': overall_percentage
1139
+ }
1140
+ }
1141
+
1142
+ def get_incomplete_rows(df, editable_cols):
1143
+ """Hitta rader där minst ett editerbart fält är tomt"""
1144
+ incomplete_mask = pd.Series([False] * len(df), index=df.index)
1145
+
1146
+ for col in editable_cols:
1147
+ if col in df.columns:
1148
+ # Markera rader där cellen är tom
1149
+ empty_mask = df[col].apply(lambda x: not bool(x and str(x).strip() != ''))
1150
+ incomplete_mask = incomplete_mask | empty_mask
1151
+
1152
+ return incomplete_mask
1153
+
1154
+ def style_empty_cells(df, editable_cols):
1155
+ """Returnera styling-funktion för att markera tomma celler"""
1156
+ def highlight_empty(row):
1157
+ styles = [''] * len(row)
1158
+ for idx, (col_name, value) in enumerate(row.items()):
1159
+ if col_name in editable_cols:
1160
+ # Markera om värdet är tomt eller None
1161
+ if pd.isna(value) or str(value).strip() == '' or str(value).strip() == '0':
1162
+ styles[idx] = 'background-color: #FFE5E5; border: 2px solid #DC3545;'
1163
+ return styles
1164
+
1165
+ return highlight_empty
1166
+
1167
  def get_column_config(df):
1168
  """Generera kolumnkonfiguration för data_editor med beskrivningar och dropdowns"""
1169
  config = {}
 
1264
  }
1265
 
1266
  /* Röd triangel-indikator för editerbara kolumner */
1267
+ /* Markera editerbara kolumnrubriker */
1268
+ [data-testid="stDataFrame"] thead th[aria-label*="🔺"] {
1269
  position: relative;
1270
+ background-color: #FFF4E6 !important;
1271
+ border: 2px solid #FF9800 !important;
1272
+ font-weight: bold !important;
1273
  }
1274
 
1275
+ [data-testid="stDataFrame"] thead th[aria-label*="🔺"]::after {
1276
  content: "";
1277
  position: absolute;
1278
  top: 0;
 
1285
  z-index: 10;
1286
  }
1287
 
1288
+ /* Hover-effekt för editerbara kolumnrubriker */
1289
+ [data-testid="stDataFrame"] thead th[aria-label*="🔺"]:hover {
1290
+ background-color: #FFE5CC !important;
1291
+ }
1292
+
1293
+ /* VIKTIGT: Markera alla CELLER i editerbara kolumner med ljusorange bakgrund */
1294
+ /* Vi använder nth-child för att rikta in oss på specifika kolumner */
1295
+ /* Detta måste justeras baserat på vilka kolumner som är editerbara */
1296
+ [data-testid="stDataFrame"] tbody td {
1297
+ position: relative;
1298
+ }
1299
+
1300
+ /* Lägg till en subtil border på alla celler för bättre läsbarhet */
1301
+ [data-testid="stDataFrame"] td,
1302
+ [data-testid="stDataFrame"] th {
1303
+ border: 1px solid #E0E0E0 !important;
1304
+ }
1305
+
1306
+ /* Styla editerbara celler i data_editor - de som inte är disabled */
1307
+ div[data-testid="stDataFrameResizable"] input:not(:disabled),
1308
+ div[data-testid="stDataFrameResizable"] textarea:not(:disabled) {
1309
+ background-color: #FFF9F0 !important;
1310
+ border: 2px solid #FFB74D !important;
1311
+ border-radius: 4px;
1312
+ }
1313
+
1314
+ /* Hover-effekt på editerbara celler */
1315
+ div[data-testid="stDataFrameResizable"] input:not(:disabled):hover,
1316
+ div[data-testid="stDataFrameResizable"] textarea:not(:disabled):hover {
1317
  background-color: #FFF3E0 !important;
1318
+ border-color: #FF9800 !important;
1319
+ }
1320
+
1321
+ /* Focus-effekt på editerbara celler */
1322
+ div[data-testid="stDataFrameResizable"] input:not(:disabled):focus,
1323
+ div[data-testid="stDataFrameResizable"] textarea:not(:disabled):focus {
1324
+ background-color: #FFFFFF !important;
1325
+ border-color: #FF5722 !important;
1326
+ box-shadow: 0 0 0 2px rgba(255, 87, 34, 0.2) !important;
1327
+ }
1328
+
1329
+ /* Disabled/readonly celler får neutral färg */
1330
+ div[data-testid="stDataFrameResizable"] input:disabled,
1331
+ div[data-testid="stDataFrameResizable"] textarea:disabled {
1332
+ background-color: #F5F5F5 !important;
1333
+ border: 1px solid #E0E0E0 !important;
1334
  }
1335
 
1336
  .excel-info-box {
 
1981
 
1982
  **Kontrollera att uppgifterna i låsta celler stämmer.** Om något verkar fel, mejla till [migration@chargenode.eu](mailto:migration@chargenode.eu) så hjälper vi dig.
1983
  """)
1984
+
1985
+ # ============================================================================
1986
+ # KOMPLETTERINGSSTATISTIK - Ny sektion
1987
+ # ============================================================================
1988
+ st.markdown("---")
1989
+ st.markdown("### 📈 Kompletteringsstatus")
1990
+
1991
+ # Beräkna komplettering
1992
+ visible_editable = [col for col in EDITABLE_COLUMNS if col in company_areas.columns and col not in HIDDEN_COLUMNS]
1993
+
1994
+ if visible_editable:
1995
+ # Total komplettering
1996
+ total_cells = len(company_areas) * len(visible_editable)
1997
+ filled_cells = 0
1998
+
1999
+ for col in visible_editable:
2000
+ filled_cells += company_areas[col].notna().sum()
2001
+ # Räkna också icke-tomma strängar
2002
+ filled_cells += (company_areas[col].astype(str).str.strip() != '').sum()
2003
+ # Dra bort dubbelräkning
2004
+ filled_cells -= company_areas[col].notna().sum()
2005
+
2006
+ # Bättre beräkning: räkna celler som har värde OCH inte är tomma strängar
2007
+ filled_cells = 0
2008
+ for col in visible_editable:
2009
+ filled_cells += ((company_areas[col].notna()) & (company_areas[col].astype(str).str.strip() != '')).sum()
2010
+
2011
+ completion_pct = (filled_cells / total_cells * 100) if total_cells > 0 else 0
2012
+
2013
+ # Metrics i kolumner
2014
+ metric_col1, metric_col2, metric_col3, metric_col4 = st.columns(4)
2015
+
2016
+ with metric_col1:
2017
+ st.metric(
2018
+ label="✅ Kompletteringsgrad",
2019
+ value=f"{completion_pct:.0f}%",
2020
+ help="Procent av alla editerbara fält som är ifyllda"
2021
+ )
2022
+
2023
+ with metric_col2:
2024
+ st.metric(
2025
+ label="📝 Ifyllda fält",
2026
+ value=f"{filled_cells}/{total_cells}",
2027
+ help="Antal ifyllda fält av totalt antal editerbara fält"
2028
+ )
2029
+
2030
+ with metric_col3:
2031
+ # Räkna kompletta rader (alla editerbara fält ifyllda)
2032
+ complete_rows = 0
2033
+ for idx in range(len(company_areas)):
2034
+ row_complete = True
2035
+ for col in visible_editable:
2036
+ val = company_areas.iloc[idx][col]
2037
+ if pd.isna(val) or str(val).strip() == '':
2038
+ row_complete = False
2039
+ break
2040
+ if row_complete:
2041
+ complete_rows += 1
2042
+
2043
+ st.metric(
2044
+ label="✨ Kompletta områden",
2045
+ value=f"{complete_rows}/{len(company_areas)}",
2046
+ help="Områden där alla editerbara fält är ifyllda"
2047
+ )
2048
+
2049
+ with metric_col4:
2050
+ incomplete_rows = len(company_areas) - complete_rows
2051
+ st.metric(
2052
+ label="⚠️ Ofullständiga områden",
2053
+ value=incomplete_rows,
2054
+ help="Områden som behöver mer information"
2055
+ )
2056
+
2057
+ # Progress bar
2058
+ st.progress(completion_pct / 100, text=f"Total komplettering: {completion_pct:.1f}%")
2059
+
2060
+ # Status per kolumn - Expanderbar sektion
2061
+ with st.expander("📋 Detaljerad status per fält", expanded=False):
2062
+ st.markdown("**Se hur många områden som har fyllt i varje fält:**")
2063
+
2064
+ for col in visible_editable:
2065
+ filled = ((company_areas[col].notna()) & (company_areas[col].astype(str).str.strip() != '')).sum()
2066
+ total = len(company_areas)
2067
+ pct = (filled / total * 100) if total > 0 else 0
2068
+
2069
+ # Färgkod baserat på komplettering
2070
+ if pct >= 90:
2071
+ status_emoji = "🟢"
2072
+ elif pct >= 50:
2073
+ status_emoji = "🟡"
2074
+ else:
2075
+ status_emoji = "🔴"
2076
+
2077
+ col_left, col_right = st.columns([4, 1])
2078
+ with col_left:
2079
+ st.progress(pct / 100, text=f"{status_emoji} {col}")
2080
+ with col_right:
2081
+ st.caption(f"{filled}/{total} ({pct:.0f}%)")
2082
+
2083
+ # Filter-sektion
2084
+ st.markdown("---")
2085
+ filter_col1, filter_col2 = st.columns([2, 3])
2086
+
2087
+ with filter_col1:
2088
+ view_filter = st.radio(
2089
+ "🔍 Visa:",
2090
+ ["📋 Alla områden", "⚠️ Endast ofullständiga", "✅ Endast kompletta"],
2091
+ horizontal=False,
2092
+ help="Filtrera tabellen för att fokusera på det som behöver göras"
2093
+ )
2094
+
2095
+ with filter_col2:
2096
+ if view_filter == "⚠️ Endast ofullständiga":
2097
+ st.info("💡 **Tips:** Fokusera på att fylla i de röd-markerade fälten i dessa områden först!")
2098
+ elif view_filter == "✅ Endast kompletta":
2099
+ st.success("🎉 **Bra jobbat!** Dessa områden har all nödvändig information ifylld.")
2100
+ else:
2101
+ st.info(f"📊 Visar alla {len(company_areas)} områden")
2102
+
2103
  st.markdown("<br>", unsafe_allow_html=True)
2104
 
2105
+ # Applicera filter baserat på användarens val
2106
+ company_areas_filtered = company_areas.copy()
2107
+
2108
+ if visible_editable and 'view_filter' in locals():
2109
+ if view_filter == "⚠️ Endast ofullständiga":
2110
+ # Filtrera till rader där minst ett editerbart fält är tomt
2111
+ mask = pd.Series([False] * len(company_areas))
2112
+ for idx in range(len(company_areas)):
2113
+ for col in visible_editable:
2114
+ val = company_areas.iloc[idx][col]
2115
+ if pd.isna(val) or str(val).strip() == '':
2116
+ mask.iloc[idx] = True
2117
+ break
2118
+ company_areas_filtered = company_areas[mask]
2119
+
2120
+ if len(company_areas_filtered) == 0:
2121
+ st.success("🎉 Fantastiskt! Alla områden är kompletta!")
2122
+ st.balloons()
2123
+
2124
+ elif view_filter == "✅ Endast kompletta":
2125
+ # Filtrera till rader där alla editerbara fält är ifyllda
2126
+ mask = pd.Series([True] * len(company_areas))
2127
+ for idx in range(len(company_areas)):
2128
+ for col in visible_editable:
2129
+ val = company_areas.iloc[idx][col]
2130
+ if pd.isna(val) or str(val).strip() == '':
2131
+ mask.iloc[idx] = False
2132
+ break
2133
+ company_areas_filtered = company_areas[mask]
2134
+
2135
+ if len(company_areas_filtered) == 0:
2136
+ st.warning("⚠️ Inga kompletta områden än. Börja fylla i de editerbara fälten!")
2137
+
2138
  # Ta bort dolda kolumner och sätt kolumnordning med Fastighetsnamn först
2139
+ company_areas_display = company_areas_filtered.drop(columns=HIDDEN_COLUMNS, errors='ignore')
2140
 
2141
  # Skapa kolumnordning med Fastighetsnamn först (för bättre synlighet vid scrolling)
2142
  column_order = ['Fastighetsnamn'] + [col for col in company_areas_display.columns if col != 'Fastighetsnamn']
 
2144
 
2145
  column_config = get_column_config(company_areas_display)
2146
 
2147
+ # Visa antal rader som visas
2148
+ if len(company_areas_display) > 0:
2149
+ st.markdown(f"""
2150
+ <div style='background-color: #E3F2FD; padding: 1rem; border-radius: 8px; margin: 1rem 0; border-left: 4px solid #2196F3;'>
2151
+ <strong>📍 Visar {len(company_areas_display)} av {len(company_areas)} områden</strong><br>
2152
+ <small>💡 <strong>Tips:</strong> Editerbara celler (🔺) har orange bakgrund och ram. Klicka i en cell för att börja redigera. Ändringar sparas automatiskt.</small>
2153
+ </div>
2154
+ """, unsafe_allow_html=True)
2155
+
2156
  # Container för att förhindra scroll-hopp
2157
  table_container = st.container()
2158