stash
This commit is contained in:
parent
7d9f67a77a
commit
3299c97392
13 changed files with 1407 additions and 327 deletions
143
frontend/src/views/ShortId.vue
Normal file
143
frontend/src/views/ShortId.vue
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
<template>
|
||||
<BaseLayout hide-search>
|
||||
<main class="content">
|
||||
<div class="container-fluid p-0">
|
||||
<div class="card">
|
||||
<div class="card-header">Decoded</div>
|
||||
<div class="card-body">
|
||||
<ul>
|
||||
<li v-for="(value, index) in decoded" :key="index">{{ value }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">Deserialized</div>
|
||||
<div class="card-body">
|
||||
<p>kind: {{ deserialized.kind }}</p>
|
||||
<ul>
|
||||
<li v-for="(value, name) in fields" :key="name">{{ name }}: {{ value }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-header">Examples</div>
|
||||
<table class="table table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Kind</th>
|
||||
<th>Fields</th>
|
||||
<th>Serialized</th>
|
||||
<th>Bits</th>
|
||||
<th>Token</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="example in examples" :key="example.token">
|
||||
<td>{{ example.kind }}</td>
|
||||
<td>
|
||||
<span v-for="(value, name) in example.fields" :key="name" class="me-2">
|
||||
{{ name }}: {{ value }}
|
||||
</span>
|
||||
</td>
|
||||
<td>[{{ example.ints.join(', ') }}]</td>
|
||||
<td><code>{{ example.bits }}</code></td>
|
||||
<td>
|
||||
<router-link :to="'/' + example.token">{{ example.token }}</router-link>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</BaseLayout>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BaseLayout from '@/components/BaseLayout.vue';
|
||||
import {decodeShortId, deserializeShortId, encodeShortId, serializeShortId} from '@/short-id';
|
||||
|
||||
const EXAMPLES = [
|
||||
{kind: 'item', owner_identity_id: 7, item_local_id: 42},
|
||||
{kind: 'storage_location', owner_identity_id: 3, storage_location_id: 1000},
|
||||
{kind: 'category', category_id: 5},
|
||||
{kind: 'workflow', owner_identity_id: 2, workflow_id: 9},
|
||||
{kind: 'group', group_id: 11},
|
||||
{kind: 'file', file_id: 123},
|
||||
];
|
||||
|
||||
// Debug-only display helper, kept out of short-id.js's production library: mirrors its bit-packing
|
||||
// rules (2-bit kind tag with an all-ones escape, 4-bit continuation chunks, see
|
||||
// docs/handles-and-shortids.md) just to show them, recomputed straight from an already-serialized
|
||||
// `ints` list rather than re-parsing a token.
|
||||
const KIND_TAG_BITS = 2;
|
||||
const CHUNK_BITS = 4;
|
||||
const DIRECT_KIND_COUNT = 2 ** KIND_TAG_BITS - 1;
|
||||
|
||||
function chunkedIntBits(value, chunkBits) {
|
||||
value = BigInt(value);
|
||||
const mask = (1n << BigInt(chunkBits)) - 1n;
|
||||
const chunks = [];
|
||||
let remaining = value;
|
||||
do {
|
||||
chunks.unshift(remaining & mask);
|
||||
remaining >>= BigInt(chunkBits);
|
||||
} while (remaining > 0n);
|
||||
return chunks.map((chunk, i) => {
|
||||
const continuation = i === chunks.length - 1 ? '0' : '1';
|
||||
return continuation + chunk.toString(2).padStart(chunkBits, '0');
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function shortIdBitSegments(ints) {
|
||||
const [kindIndex, ...fieldValues] = ints;
|
||||
const segments = [];
|
||||
if (kindIndex < DIRECT_KIND_COUNT) {
|
||||
segments.push(kindIndex.toString(2).padStart(KIND_TAG_BITS, '0'));
|
||||
} else {
|
||||
segments.push('1'.repeat(KIND_TAG_BITS));
|
||||
segments.push(chunkedIntBits(kindIndex - DIRECT_KIND_COUNT, CHUNK_BITS));
|
||||
}
|
||||
fieldValues.forEach(value => segments.push(chunkedIntBits(value, CHUNK_BITS)));
|
||||
|
||||
const totalBits = segments.join('').length;
|
||||
const paddingBits = (6 - (totalBits % 6)) % 6;
|
||||
if (paddingBits > 0) {
|
||||
segments.push('0'.repeat(paddingBits));
|
||||
}
|
||||
return segments.join(' ');
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'ShortId',
|
||||
components: {
|
||||
BaseLayout
|
||||
},
|
||||
props: {
|
||||
short_id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
decoded() {
|
||||
return decodeShortId(this.short_id);
|
||||
},
|
||||
deserialized() {
|
||||
return deserializeShortId(this.decoded);
|
||||
},
|
||||
fields() {
|
||||
const {kind, ...fields} = this.deserialized;
|
||||
return fields;
|
||||
},
|
||||
examples() {
|
||||
return EXAMPLES.map(named => {
|
||||
const {kind, ...fields} = named;
|
||||
const ints = serializeShortId(named);
|
||||
const token = encodeShortId(ints);
|
||||
return {kind, fields, ints, token, bits: shortIdBitSegments(ints)};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue