Skip to content
Closed
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
50 changes: 47 additions & 3 deletions modules/ext.rules/components/App.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<template>
<div v-if="errorMessage" class="error-banner">
{{ errorMessage }}
</div>
<edit-rule
v-model:open="isFormVisible"
:rule="ruleToEdit"
Expand Down Expand Up @@ -35,7 +38,7 @@ module.exports = defineComponent( {
/** @type {import('vue').Ref<Rule | null>} */
const ruleToEdit = ref( null );
const { rules, addRule, updateRule, deleteRule, saveRules } = useRules( getInitialRules() );

const errorMessage = ref('');
const api = new mw.Api();
provide( 'api', api );
const title = mw.config.get( 'wgPageName' );
Expand Down Expand Up @@ -87,8 +90,21 @@ module.exports = defineComponent( {
);
}
}
// Watch for changes in rules and save them to the API
//return an error message if saving fails
watch( rules, async () => {
errorMessage.value = '';
try {
await saveRules( api, title );
} catch ( error ) {
console.error( 'Save failed:', error );
errorMessage.value = 'Failed to save rules. Please try again.';
mw.notify( errorMessage.value, { type: 'error' } );
}
}, { deep: true } );

watch( rules, () => saveRules( api, title ), { deep: true } );
}
}, { deep: true } );

return {
rules,
Expand All @@ -97,8 +113,36 @@ module.exports = defineComponent( {
onAddRule,
onEditRule,
onDeleteRule,
onSaveRule
onSaveRule,
errorMessage
};
}
} );

</script>
<style scoped>
.error-banner {
background-color: #ffe6e6;
color: #cc0000;
border: 1px solid #ffcccc;
padding: 12px 16px;
border-radius: 6px;
margin: 12px 0;
font-weight: 500;
font-family: sans-serif;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
animation: fadeIn 0.3s ease-in-out;
}

@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-4px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>

34 changes: 22 additions & 12 deletions modules/ext.rules/composables/useRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { ref } = require( 'vue' );
/**
* @typedef {object} RulesComposable
* @property {import('vue').Ref<boolean>} saving
* @property {import('vue').Ref<string|null>} saveError
* @property {import('vue').Ref<Rule[]>} rules
* @property {( rule: Rule ) => Rule} addRule
* @property {( originalRule: Rule, updatedRule: Rule ) => Rule | null} updateRule
Expand All @@ -18,6 +19,7 @@ const { ref } = require( 'vue' );
*/
function useRules( initialRules = [] ) {
const saving = ref( false );
const saveError = ref(' ');
/** @type {import('vue').Ref<Rule[]>} */
const rules = ref( [ ...initialRules ] );

Expand Down Expand Up @@ -66,22 +68,30 @@ function useRules( initialRules = [] ) {
* @param {string} title
* @return {Promise<any>}
*/
async function saveRules( api, title ) {
saving.value = true;
try {
const content = JSON.stringify( { rules: rules.value } );
return await api.postWithToken( 'csrf', {
action: 'edit',
title,
text: content
} );
} finally {
saving.value = false;
}
async function saveRules(api, title) {
saving.value = true;
saveError.value = null;

try {
const content = JSON.stringify({ rules: rules.value });
return await api.postWithToken('csrf', {
action: 'edit',
title,
text: content
});
} catch (error) {
console.error('Failed to save rules:', error);
saveError.value = error;
return null;
} finally {
saving.value = false;
}
}


return {
saving,
saveError,
rules,
addRule,
updateRule,
Expand Down
Loading