Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions add_missing_primary_names.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env python3
"""
Add pm_name fields ONLY to entities that don't have them yet
"""

import re

# Only add to entities that are missing pm_name
ENTITIES_MISSING_PM_NAME = [
("pm_EvaluationQuestion", "pm_name", "Name", "Question title"),
("pm_IDPEntry", "pm_name", "Name", "Development goal title"),
("pm_Goal", "pm_name", "Name", "Goal title"),
]

# Primary name field template
PRIMARY_NAME_TEMPLATE = """ <attribute PhysicalName="{physical_name}">
<Type>nvarchar</Type>
<Name>{logical_name}</Name>
<LogicalName>{logical_name}</LogicalName>
<RequiredLevel>required</RequiredLevel>
<DisplayMask>PrimaryName|ValidForAdvancedFind|ValidForForm|ValidForGrid|RequiredForForm</DisplayMask>
<ImeMode>auto</ImeMode>
<ValidForUpdateApi>1</ValidForUpdateApi>
<ValidForReadApi>1</ValidForReadApi>
<ValidForCreateApi>1</ValidForCreateApi>
<IsCustomField>1</IsCustomField>
<IsAuditEnabled>0</IsAuditEnabled>
<IsSecured>0</IsSecured>
<IntroducedVersion>2.0.0.0</IntroducedVersion>
<IsCustomizable>1</IsCustomizable>
<IsRenameable>1</IsRenameable>
<CanModifySearchSettings>1</CanModifySearchSettings>
<CanModifyRequirementLevelSettings>1</CanModifyRequirementLevelSettings>
<CanModifyAdditionalSettings>1</CanModifyAdditionalSettings>
<SourceType>0</SourceType>
<IsGlobalFilterEnabled>0</IsGlobalFilterEnabled>
<IsSortableEnabled>1</IsSortableEnabled>
<CanModifyGlobalFilterSettings>1</CanModifyGlobalFilterSettings>
<CanModifyIsSortableSettings>1</CanModifyIsSortableSettings>
<IsDataSourceSecret>0</IsDataSourceSecret>
<AutoNumberFormat></AutoNumberFormat>
<IsSearchable>1</IsSearchable>
<IsFilterable>1</IsFilterable>
<IsRetrievable>1</IsRetrievable>
<IsLocalizable>0</IsLocalizable>
<Format>Text</Format>
<MaxLength>100</MaxLength>
<displaynames>
<displayname description="{display_name}" languagecode="1033" />
</displaynames>
<Descriptions>
<Description description="{description}" languagecode="1033" />
</Descriptions>
</attribute>
"""

print("Adding pm_name fields to entities that are missing them...")
print()

# Read the file
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'r', encoding='utf-8') as f:
content = f.read()

for entity_name, field_name, display_name, description in ENTITIES_MISSING_PM_NAME:
# Create the primary name field
primary_name_field = PRIMARY_NAME_TEMPLATE.format(
physical_name=field_name,
logical_name=field_name,
display_name=display_name,
description=description
)

# Insert after the primary key attribute
pattern = f'(<entity Name="{entity_name}">.*?</attribute>)(\\s+<attribute)'
replacement = f'\\1\n{primary_name_field}\\2'

old_content = content
content = re.sub(pattern, replacement, content, count=1, flags=re.DOTALL)

if content != old_content:
print(f"✓ Added pm_name to {entity_name}")
else:
print(f"✗ Failed to add pm_name to {entity_name}")

# Write back
print()
print("Writing updated customizations.xml...")
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'w', encoding='utf-8') as f:
f.write(content)

lines = len(content.split('\n'))
print(f"✓ File updated: {lines} lines")
print("✓ Primary name fields added to entities that were missing them")
101 changes: 101 additions & 0 deletions add_primary_name_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#!/usr/bin/env python3
"""
Add primary name fields to all custom entities
Every Dataverse entity needs a primary name field (nvarchar with PrimaryName in DisplayMask)
"""

import re

# Entity names and their primary name field definitions
ENTITIES = [
("pm_StaffMember", "pm_name", "Name", "Employee name"),
("pm_EvaluationQuestion", "pm_name", "Name", "Question title"),
("pm_WeeklyEvaluation", "pm_name", "Name", "Evaluation name"),
("pm_SelfEvaluation", "pm_name", "Name", "Self-evaluation name"),
("pm_IDPEntry", "pm_name", "Name", "Development goal title"),
("pm_MeetingNote", "pm_name", "Name", "Meeting note title"),
("pm_Goal", "pm_name", "Name", "Goal title"),
("pm_Recognition", "pm_name", "Name", "Recognition title"),
("pm_ActionItem", "pm_name", "Name", "Action item description"),
]

# Primary name field template based on Microsoft samples
PRIMARY_NAME_TEMPLATE = """ <attribute PhysicalName="{physical_name}">
<Type>nvarchar</Type>
<Name>{logical_name}</Name>
<LogicalName>{logical_name}</LogicalName>
<RequiredLevel>required</RequiredLevel>
<DisplayMask>PrimaryName|ValidForAdvancedFind|ValidForForm|ValidForGrid|RequiredForForm</DisplayMask>
<ImeMode>auto</ImeMode>
<ValidForUpdateApi>1</ValidForUpdateApi>
<ValidForReadApi>1</ValidForReadApi>
<ValidForCreateApi>1</ValidForCreateApi>
<IsCustomField>1</IsCustomField>
<IsAuditEnabled>0</IsAuditEnabled>
<IsSecured>0</IsSecured>
<IntroducedVersion>2.0.0.0</IntroducedVersion>
<IsCustomizable>1</IsCustomizable>
<IsRenameable>1</IsRenameable>
<CanModifySearchSettings>1</CanModifySearchSettings>
<CanModifyRequirementLevelSettings>1</CanModifyRequirementLevelSettings>
<CanModifyAdditionalSettings>1</CanModifyAdditionalSettings>
<SourceType>0</SourceType>
<IsGlobalFilterEnabled>0</IsGlobalFilterEnabled>
<IsSortableEnabled>1</IsSortableEnabled>
<CanModifyGlobalFilterSettings>1</CanModifyGlobalFilterSettings>
<CanModifyIsSortableSettings>1</CanModifyIsSortableSettings>
<IsDataSourceSecret>0</IsDataSourceSecret>
<AutoNumberFormat></AutoNumberFormat>
<IsSearchable>1</IsSearchable>
<IsFilterable>1</IsFilterable>
<IsRetrievable>1</IsRetrievable>
<IsLocalizable>0</IsLocalizable>
<Format>Text</Format>
<MaxLength>100</MaxLength>
<displaynames>
<displayname description="{display_name}" languagecode="1033" />
</displaynames>
<Descriptions>
<Description description="{description}" languagecode="1033" />
</Descriptions>
</attribute>
"""

print("Adding primary name fields to all entities...")
print()

# Read the file
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'r', encoding='utf-8') as f:
content = f.read()

for entity_name, field_name, display_name, description in ENTITIES:
# Create the primary name field for this entity
primary_name_field = PRIMARY_NAME_TEMPLATE.format(
physical_name=field_name,
logical_name=field_name,
display_name=display_name,
description=description
)

# Find the pattern: after primarykey attribute, before any other attributes
# Insert the primary name field right after the primary key
pattern = f'(<entity Name="{entity_name}">.*?</attribute>)(\\s+<attribute)'
replacement = f'\\1\n{primary_name_field}\\2'

old_content = content
content = re.sub(pattern, replacement, content, count=1, flags=re.DOTALL)

if content != old_content:
print(f"✓ Added primary name field to {entity_name}")
else:
print(f"✗ Failed to add primary name field to {entity_name}")

# Write back
print()
print("Writing updated customizations.xml...")
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'w', encoding='utf-8') as f:
f.write(content)

lines = len(content.split('\n'))
print(f"✓ File updated: {lines} lines")
print("✓ Primary name fields added to all 9 entities")
68 changes: 68 additions & 0 deletions fix_primary_name_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env python3
"""
Fix primary name fields by updating existing pm_name fields to include PrimaryName in DisplayMask
instead of adding duplicate fields
"""

import re

print("Updating existing pm_name fields to be primary name fields...")
print()

# Read the file
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'r', encoding='utf-8') as f:
content = f.read()

# Count how many pm_name fields we find
count = 0

# Find all pm_name attribute blocks and update their DisplayMask to include PrimaryName
# Pattern: find attribute blocks with Name>pm_name</Name> and update DisplayMask

# Strategy: Find each pm_name attribute and ensure it has PrimaryName in DisplayMask
pattern = r'(<attribute PhysicalName="pm_name">.*?<DisplayMask>)([^<]+)(</DisplayMask>.*?</attribute>)'

def fix_display_mask(match):
global count
prefix = match.group(1)
display_mask = match.group(2)
suffix = match.group(3)

# Check if PrimaryName is already in the mask
if 'PrimaryName' not in display_mask:
# Add PrimaryName to the beginning
new_mask = 'PrimaryName|' + display_mask
count += 1
print(f"✓ Updated pm_name field (was: {display_mask}, now: {new_mask})")
return prefix + new_mask + suffix
else:
print(f" pm_name already has PrimaryName")
return match.group(0)

content = re.sub(pattern, fix_display_mask, content, flags=re.DOTALL)

# Also need to ensure pm_name fields are required
# Update RequiredLevel if it's not 'required' or 'applicationrequired'
pattern2 = r'(<attribute PhysicalName="pm_name">.*?<RequiredLevel>)([^<]+)(</RequiredLevel>.*?</attribute>)'

def fix_required_level(match):
prefix = match.group(1)
req_level = match.group(2)
suffix = match.group(3)

if req_level not in ['required', 'applicationrequired', 'systemrequired']:
print(f" Updated RequiredLevel from {req_level} to required")
return prefix + 'required' + suffix
return match.group(0)

content = re.sub(pattern2, fix_required_level, content, flags=re.DOTALL)

# Write back
print()
print("Writing updated customizations.xml...")
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'w', encoding='utf-8') as f:
f.write(content)

lines = len(content.split('\n'))
print(f"✓ File updated: {lines} lines")
print(f"✓ Updated {count} pm_name fields to be primary name fields")
Binary file modified releases/PerformanceManagement_2_0_0_0.zip
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
75 changes: 75 additions & 0 deletions remove_system_fields.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""
Remove system fields from entity definitions in customizations.xml
For new entities in unmanaged solutions, Dataverse creates system fields automatically
"""

import re
import xml.etree.ElementTree as ET

print("Removing system fields from all entities...")
print()

# Read the file
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'r', encoding='utf-8') as f:
content = f.read()

# Find all attribute blocks that have IsCustomField>0</IsCustomField> (system fields)
# We need to remove entire attribute blocks from <attribute PhysicalName="..."> to </attribute>

# Strategy: Parse and rebuild, keeping only custom fields and primary key
lines = content.split('\n')
new_lines = []
inside_attribute = False
attribute_buffer = []
keep_attribute = False
is_primary_key = False

for line in lines:
# Check if we're starting an attribute
if '<attribute PhysicalName=' in line:
inside_attribute = True
attribute_buffer = [line]
keep_attribute = False
is_primary_key = False
continue

# If we're inside an attribute
if inside_attribute:
attribute_buffer.append(line)

# Check if it's a primary key (always keep these)
if '<Type>primarykey</Type>' in line:
is_primary_key = True
keep_attribute = True

# Check if it's a custom field
if '<IsCustomField>1</IsCustomField>' in line:
keep_attribute = True

# Check if we're ending the attribute
if '</attribute>' in line:
inside_attribute = False

# Only keep if it's custom or primary key
if keep_attribute or is_primary_key:
new_lines.extend(attribute_buffer)
else:
# This was a system field, skip it
pass

attribute_buffer = []
continue
else:
# Not inside an attribute, keep the line
new_lines.append(line)

new_content = '\n'.join(new_lines)

# Write back
print("Writing updated customizations.xml...")
with open('/home/user/ContinousPerformanceManagementApp/solution/Other/Customizations.xml', 'w', encoding='utf-8') as f:
f.write(new_content)

print(f"✓ File updated: {len(new_lines)} lines")
print("✓ System fields removed, keeping only custom fields and primary keys")
Loading